Added experimental C APIs to build a stack of dataset + iterator nodes that
authorMingsheng Hong <hongm@google.com>
Mon, 26 Mar 2018 17:51:21 +0000 (10:51 -0700)
committerTensorFlower Gardener <gardener@tensorflow.org>
Mon, 26 Mar 2018 17:53:46 +0000 (10:53 -0700)
reads imagenet TFRecord files.

PiperOrigin-RevId: 190488817

tensorflow/c/BUILD
tensorflow/c/c_api_experimental.cc
tensorflow/c/c_api_experimental.h
tensorflow/c/c_api_experimental_test.cc
tensorflow/c/testdata/tf_record [new file with mode: 0644]

index d096647..426f97b 100644 (file)
@@ -220,6 +220,7 @@ tf_cc_test(
     name = "c_api_experimental_test",
     size = "small",
     srcs = ["c_api_experimental_test.cc"],
+    data = ["testdata/tf_record"],
     linkopts = select({
         "//tensorflow:darwin": ["-headerpad_max_install_names"],
         "//conditions:default": [],
@@ -230,6 +231,7 @@ tf_cc_test(
     deps = [
         ":c_api_experimental",
         ":c_test_util",
+        "//tensorflow/core:lib",
         "//tensorflow/core:test",
         "//tensorflow/core:test_main",
     ],
index 8593a8e..1c809cb 100644 (file)
@@ -22,10 +22,15 @@ limitations under the License.
 #include "tensorflow/core/lib/strings/strcat.h"
 #include "tensorflow/core/protobuf/config.pb.h"
 
+using tensorflow::FunctionDef;
 using tensorflow::Node;
 using tensorflow::NodeBuilder;
 using tensorflow::Status;
-using tensorflow::Tensor;
+
+namespace {
+typedef std::unique_ptr<TF_Function, decltype(&TF_DeleteFunction)>
+    UniqueFuncPtr;
+}
 
 // struct TF_Operation { tensorflow::Node node; };
 static TF_Operation* ToTF_Operation(Node* node) {
@@ -102,8 +107,7 @@ void TF_ShutdownTPU(TF_Session* session, TF_Status* status) {
                 /*run_metadata*/ nullptr, status);
 }
 
-TF_CAPI_EXPORT extern const char* TF_GraphDebugString(TF_Graph* graph,
-                                                      size_t* len) {
+const char* TF_GraphDebugString(TF_Graph* graph, size_t* len) {
   tensorflow::mutex_lock c(graph->mu);
   const auto& debug_str = graph->graph.ToGraphDefDebug().DebugString();
   *len = debug_str.size();
@@ -112,55 +116,56 @@ TF_CAPI_EXPORT extern const char* TF_GraphDebugString(TF_Graph* graph,
   return ret;
 }
 
-// TODO(hongm): Replace this will a real implementation.
-static tensorflow::Status BuildDatasetTest(TF_Graph* dataset_graph,
-                                           Node** dataset_node) {
-  tensorflow::mutex_lock c(dataset_graph->mu);
-  Tensor const_t(tensorflow::DT_INT32, tensorflow::TensorShape({}));
-  const_t.flat<tensorflow::int32>()(0) = 1;
-
-  Node* const_node;
-  TF_RETURN_IF_ERROR(NodeBuilder("Const", "Const")
-                         .Attr("dtype", tensorflow::DT_INT32)
-                         .Attr("value", const_t)
-                         .Finalize(&dataset_graph->graph, &const_node));
-
-  std::vector<NodeBuilder::NodeOut> input_list;
-  input_list.push_back(NodeBuilder::NodeOut(const_node, 0));
-
-  return NodeBuilder("TensorDataset", "TensorDataset")
-      .Input(input_list)
-      .Attr("Toutput_types", {tensorflow::DT_INT32})
-      .Attr("output_shapes", {tensorflow::TensorShapeProto()})
-      .Finalize(&dataset_graph->graph, dataset_node);
-}
-
-//  On success, returns a newly created TF_Function instance from
-//  `text_proto`. It must be deleted by calling TF_DeleteFunction.
-static TF_Function* CreateFunctionFromTextProto(const char* text_proto,
-                                                TF_Status* status) {
-  tensorflow::FunctionDef fdef;
-  if (!tensorflow::protobuf::TextFormat::ParseFromString(text_proto, &fdef)) {
+// On success, returns a set of TF_Function instances from `text_proto` of
+// GraphDef type. These functions must be deleted by calling TF_DeleteFunction.
+//
+// If `mutate_proto_func` is non-NULL, run it over each FunctionDef proto,
+// before creating a TF_Function out of the possibly mutated proto.
+static std::vector<UniqueFuncPtr> CreateFunctionsFromTextProto(
+    const char* text_proto,
+    std::function<void(FunctionDef*)>* mutate_proto_func, TF_Status* status) {
+  tensorflow::GraphDef gdef;
+  if (!tensorflow::protobuf::TextFormat::ParseFromString(text_proto, &gdef)) {
     status->status = tensorflow::errors::Internal(
-        "Invalid text proto for FunctionDef: ", text_proto);
-    return nullptr;
+        "Invalid text proto for GraphDef: ", text_proto);
+    return {};
+  }
+  const auto& fdef_lib = gdef.library();
+  if (fdef_lib.gradient_size() > 0) {
+    status->status = tensorflow::errors::Internal(
+        "GradientDef is not supported in reading Dataset related functions: ",
+        text_proto);
+    return {};
   }
-  std::vector<char> binary_proto_buf(fdef.ByteSizeLong());
-  fdef.SerializeToArray(binary_proto_buf.data(), binary_proto_buf.size());
-  return TF_FunctionImportFunctionDef(binary_proto_buf.data(),
-                                      binary_proto_buf.size(), status);
+  std::vector<UniqueFuncPtr> ret;
+  for (const auto& fdef : fdef_lib.function()) {
+    // Make a copy so that we can mutate it.
+    FunctionDef fdef_to_load = fdef;
+    if (mutate_proto_func) {
+      (*mutate_proto_func)(&fdef_to_load);
+    }
+    VLOG(1) << "Adding func to graph: " << fdef_to_load.DebugString();
+    std::vector<char> binary_proto_buf(fdef_to_load.ByteSizeLong());
+    fdef_to_load.SerializeToArray(binary_proto_buf.data(),
+                                  binary_proto_buf.size());
+    auto func = TF_FunctionImportFunctionDef(binary_proto_buf.data(),
+                                             binary_proto_buf.size(), status);
+    if (!status->status.ok()) return {};
+    ret.push_back(UniqueFuncPtr(func, TF_DeleteFunction));
+  }
+  return ret;
 }
 
-//  On success, returns a newly created TF_Function instance from `proto_file`,
-//  and sets `dataset_name` to the created dataset name. The returned function
-//  must be deleted by calling TF_DeleteFunction.
-//
-// TODO(hongm): Support reading the file given by `proto_file`.
-static TF_Function* LoadDatasetFunction(const char* proto_file,
-                                        std::string* dataset_name,
-                                        TF_Status* status) {
+//  On success, returns a newly created TF_Function instance encoding a dataset
+//  node stack that returns a sequence of 3 floats, and sets `dataset_name` to
+//  the created dataset name. The returned function must be deleted by calling
+//  TF_DeleteFunction.
+static UniqueFuncPtr CreateFakeDatasetFunction(std::string* dataset_name,
+                                               TF_Status* status) {
   const char* func_def = R"PREFIX(
-signature {
+library {
+  function {
+    signature {
       name: "_make_dataset_d8de2712"
       output_arg {
         name: "TensorSliceDataset"
@@ -217,112 +222,7029 @@ signature {
     ret {
       key: "TensorSliceDataset"
       value: "TensorSliceDataset:handle:0"
-    })PREFIX";
+    }
+  }
+}
+)PREFIX";
 
   *dataset_name = "_make_dataset_d8de2712";
-  return CreateFunctionFromTextProto(func_def, status);
+  auto functions = CreateFunctionsFromTextProto(
+      func_def, /*mutate_proto_func*/ nullptr, status);
+  DCHECK_EQ(functions.size(), 1);
+  return std::move(functions[0]);
 }
 
-// TODO(hongm): Use `file_path` in the implementation.
-TF_Operation* TF_MakeIteratorGetNextWithDatasets(TF_Graph* graph,
-                                                 const char* file_path,
-                                                 TF_Function** dataset_func,
-                                                 TF_Status* status) {
-  tensorflow::Status s;
-
-  // We can parameterize the function name, if we ever need more than 1
-  // iterators in a graph.
-  const std::string dataset_name = "UNIQUE_DATASET";
-
-  std::unique_ptr<TF_Graph, decltype(&TF_DeleteGraph)> dataset_graph(
-      TF_NewGraph(), TF_DeleteGraph);
-  Node* dataset_node = nullptr;
-  s = BuildDatasetTest(dataset_graph.get(), &dataset_node);
-  if (!s.ok()) {
-    status->status = s;
-    return nullptr;
-  }
-
-  TF_Output output{ToTF_Operation(dataset_node), 0};
-  std::unique_ptr<TF_Function, decltype(&TF_DeleteFunction)> result_func(
-      TF_GraphToFunction(dataset_graph.get(), dataset_name.c_str(),
-                         /*append_hash_to_fn_name*/ false,
-                         /*num_opers*/ -1,
-                         /*opers*/ nullptr,
-                         /*numinputs*/ 0,
-                         /*inputs*/ nullptr,
-                         /*noutputs*/ 1,
-                         /*outputs*/ &output,
-                         /*outputnames*/ nullptr,
-                         /*functionoptions*/ nullptr, "", status),
-      TF_DeleteFunction);
-  if (!status->status.ok()) {
-    return nullptr;
-  }
-
-  TF_GraphCopyFunction(graph, result_func.get(), /*gradient*/ nullptr, status);
-
-  if (!status->status.ok()) {
-    return nullptr;
-  }
-
-  tensorflow::mutex_lock c(graph->mu);
-
-  tensorflow::NameAttrList func;
-  func.set_name(dataset_name);
-  // Run the iterator node on CPU.
-  Node* oneshot_iterator_node;
-  std::vector<tensorflow::TensorShapeProto> output_shape_list;
-  output_shape_list.push_back(tensorflow::TensorShapeProto());
-  s = NodeBuilder("OneShotIterator", "OneShotIterator")
-          .Device("/device:CPU:0")
-          .Attr("container", "")
-          .Attr("dataset_factory", func)
-          .Attr("output_types", {tensorflow::DT_INT32})
-          .Attr("output_shapes", output_shape_list)
-          .Attr("shared_name", "")
-          .Finalize(&graph->graph, &oneshot_iterator_node);
-  if (!s.ok()) {
-    status->status = s;
-    return nullptr;
-  }
-  // Run shape inference function for each newly added node, so that more
-  // subsequent nodes can be added to the graph via C API (TF_NewOperation()).
-  s = graph->refiner.AddNode(oneshot_iterator_node);
-  if (!s.ok()) {
-    status->status = s;
-    return nullptr;
-  }
-
-  // Run the iterator node on CPU.
-  Node* getnext_node;
-  s = NodeBuilder("IteratorGetNext", "IteratorGetNext")
-          .Input(oneshot_iterator_node)
-          .Device("/device:CPU:0")
-          .Attr("output_types", {tensorflow::DT_INT32})
-          .Attr("output_shapes", output_shape_list)
-          .Finalize(&graph->graph, &getnext_node);
-  if (!s.ok()) {
-    status->status = s;
-    return nullptr;
+//  On success, returns a set of TF_Function instances encoding a dataset
+//  node stack that reads a Imagenet TFRecordFile dataset from `file_path`, and
+//  sets `dataset_name` to the created dataset name. The returned functions must
+//  be deleted by calling TF_DeleteFunction.
+static std::vector<UniqueFuncPtr> CreateImagenetDatasetFunctions(
+    const char* file_path, std::string* dataset_name, TF_Status* status) {
+  const char* func_def = R"PREFIX(
+library {
+  function {
+    signature {
+      name: "tf_map_func_91295dea"
+      input_arg {
+        name: "arg0"
+        type: DT_STRING
+      }
+      output_arg {
+        name: "FlatMapDataset"
+        type: DT_VARIANT
+      }
+      description: "A wrapper for Defun that facilitates shape inference."
+      is_stateful: true
+    }
+    node_def {
+      name: "flat_filenames/shape"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: -1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "flat_filenames"
+      op: "Reshape"
+      input: "arg0"
+      input: "flat_filenames/shape:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "Tshape"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "TensorSliceDataset"
+      op: "TensorSliceDataset"
+      input: "flat_filenames:output:0"
+      attr {
+        key: "Toutput_types"
+        value {
+          list {
+            type: DT_STRING
+          }
+        }
+      }
+      attr {
+        key: "output_shapes"
+        value {
+          list {
+            shape {
+            }
+          }
+        }
+      }
+    }
+    node_def {
+      name: "FlatMapDataset"
+      op: "FlatMapDataset"
+      input: "TensorSliceDataset:handle:0"
+      attr {
+        key: "Targuments"
+        value {
+          list {
+          }
+        }
+      }
+      attr {
+        key: "f"
+        value {
+          func {
+            name: "tf_map_func_0cc8c35b"
+          }
+        }
+      }
+      attr {
+        key: "output_shapes"
+        value {
+          list {
+            shape {
+            }
+          }
+        }
+      }
+      attr {
+        key: "output_types"
+        value {
+          list {
+            type: DT_STRING
+          }
+        }
+      }
+    }
+    ret {
+      key: "FlatMapDataset"
+      value: "FlatMapDataset:handle:0"
+    }
   }
-  // Run shape inference function for each newly added node, so that more
-  // subsequent nodes can be added to the graph via C API (TF_NewOperation()).
-  s = graph->refiner.AddNode(getnext_node);
-  if (!s.ok()) {
-    status->status = s;
-    return nullptr;
+  function {
+    signature {
+      name: "tf_map_func_0cc8c35b"
+      input_arg {
+        name: "arg0"
+        type: DT_STRING
+      }
+      output_arg {
+        name: "TFRecordDataset"
+        type: DT_VARIANT
+      }
+      description: "A wrapper for Defun that facilitates shape inference."
+      is_stateful: true
+    }
+    node_def {
+      name: "compression_type"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: ""
+          }
+        }
+      }
+    }
+    node_def {
+      name: "buffer_size"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT64
+            tensor_shape {
+            }
+            int64_val: 8388608
+          }
+        }
+      }
+    }
+    node_def {
+      name: "TFRecordDataset"
+      op: "TFRecordDataset"
+      input: "arg0"
+      input: "compression_type:output:0"
+      input: "buffer_size:output:0"
+    }
+    ret {
+      key: "TFRecordDataset"
+      value: "TFRecordDataset:handle:0"
+    }
   }
+  function {
+    signature {
+      name: "tf_map_func_74b6b15c"
+      input_arg {
+        name: "arg0"
+        type: DT_STRING
+      }
+      output_arg {
+        name: "Reshape_1"
+        type: DT_FLOAT
+      }
+      output_arg {
+        name: "sub_1"
+        type: DT_INT32
+      }
+      description: "A wrapper for Defun that facilitates shape inference."
+      is_stateful: true
+    }
+    node_def {
+      name: "ParseSingleExample/key_image/class/label"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT64
+            tensor_shape {
+            }
+            int64_val: -1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ParseSingleExample/Reshape/shape"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+              }
+            }
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ParseSingleExample/Reshape"
+      op: "Reshape"
+      input: "ParseSingleExample/key_image/class/label:output:0"
+      input: "ParseSingleExample/Reshape/shape:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "Tshape"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "ParseSingleExample/key_image/class/text"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: ""
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ParseSingleExample/Reshape_1/shape"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+              }
+            }
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ParseSingleExample/Reshape_1"
+      op: "Reshape"
+      input: "ParseSingleExample/key_image/class/text:output:0"
+      input: "ParseSingleExample/Reshape_1/shape:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "Tshape"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "ParseSingleExample/key_image/encoded"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: ""
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ParseSingleExample/Reshape_2/shape"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+              }
+            }
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ParseSingleExample/Reshape_2"
+      op: "Reshape"
+      input: "ParseSingleExample/key_image/encoded:output:0"
+      input: "ParseSingleExample/Reshape_2/shape:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "Tshape"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "ParseSingleExample/key_image/format"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: "jpeg"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ParseSingleExample/Reshape_3/shape"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+              }
+            }
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ParseSingleExample/Reshape_3"
+      op: "Reshape"
+      input: "ParseSingleExample/key_image/format:output:0"
+      input: "ParseSingleExample/Reshape_3/shape:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "Tshape"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "ParseSingleExample/ParseSingleExample"
+      op: "ParseSingleExample"
+      input: "arg0"
+      input: "ParseSingleExample/Reshape:output:0"
+      input: "ParseSingleExample/Reshape_1:output:0"
+      input: "ParseSingleExample/Reshape_2:output:0"
+      input: "ParseSingleExample/Reshape_3:output:0"
+      attr {
+        key: "Tdense"
+        value {
+          list {
+            type: DT_INT64
+            type: DT_STRING
+            type: DT_STRING
+            type: DT_STRING
+          }
+        }
+      }
+      attr {
+        key: "dense_keys"
+        value {
+          list {
+            s: "image/class/label"
+            s: "image/class/text"
+            s: "image/encoded"
+            s: "image/format"
+          }
+        }
+      }
+      attr {
+        key: "dense_shapes"
+        value {
+          list {
+            shape {
+            }
+            shape {
+            }
+            shape {
+            }
+            shape {
+            }
+          }
+        }
+      }
+      attr {
+        key: "num_sparse"
+        value {
+          i: 5
+        }
+      }
+      attr {
+        key: "sparse_keys"
+        value {
+          list {
+            s: "image/object/bbox/xmax"
+            s: "image/object/bbox/xmin"
+            s: "image/object/bbox/ymax"
+            s: "image/object/bbox/ymin"
+            s: "image/object/class/label"
+          }
+        }
+      }
+      attr {
+        key: "sparse_types"
+        value {
+          list {
+            type: DT_FLOAT
+            type: DT_FLOAT
+            type: DT_FLOAT
+            type: DT_FLOAT
+            type: DT_INT64
+          }
+        }
+      }
+    }
+    node_def {
+      name: "Reshape/shape"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+              }
+            }
+          }
+        }
+      }
+    }
+    node_def {
+      name: "Reshape"
+      op: "Reshape"
+      input: "ParseSingleExample/ParseSingleExample:dense_values:2"
+      input: "Reshape/shape:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "Tshape"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/Substr/pos"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/Substr/len"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 3
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/Substr"
+      op: "Substr"
+      input: "Reshape:output:0"
+      input: "decode_image/Substr/pos:output:0"
+      input: "decode_image/Substr/len:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/is_jpeg/Substr/pos"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/is_jpeg/Substr/len"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 3
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/is_jpeg/Substr"
+      op: "Substr"
+      input: "Reshape:output:0"
+      input: "decode_image/is_jpeg/Substr/pos:output:0"
+      input: "decode_image/is_jpeg/Substr/len:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/is_jpeg/Equal/y"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: "\377\330\377"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/is_jpeg/Equal"
+      op: "Equal"
+      input: "decode_image/is_jpeg/Substr:output:0"
+      input: "decode_image/is_jpeg/Equal/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_STRING
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/Switch"
+      op: "Switch"
+      input: "decode_image/is_jpeg/Equal:z:0"
+      input: "decode_image/is_jpeg/Equal:z:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/switch_t"
+      op: "Identity"
+      input: "decode_image/cond_jpeg/Switch:output_true:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/switch_f"
+      op: "Identity"
+      input: "decode_image/cond_jpeg/Switch:output_false:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/pred_id"
+      op: "Identity"
+      input: "decode_image/is_jpeg/Equal:z:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/check_jpeg_channels/x"
+      op: "Const"
+      input: "^decode_image/cond_jpeg/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 3
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/check_jpeg_channels/y"
+      op: "Const"
+      input: "^decode_image/cond_jpeg/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 4
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/check_jpeg_channels"
+      op: "NotEqual"
+      input: "decode_image/cond_jpeg/check_jpeg_channels/x:output:0"
+      input: "decode_image/cond_jpeg/check_jpeg_channels/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/Assert/Const"
+      op: "Const"
+      input: "^decode_image/cond_jpeg/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: "Channels must be in (None, 0, 1, 3) when decoding JPEG images"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/Assert/Assert/data_0"
+      op: "Const"
+      input: "^decode_image/cond_jpeg/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: "Channels must be in (None, 0, 1, 3) when decoding JPEG images"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/Assert/Assert"
+      op: "Assert"
+      input: "decode_image/cond_jpeg/check_jpeg_channels:z:0"
+      input: "decode_image/cond_jpeg/Assert/Assert/data_0:output:0"
+      attr {
+        key: "T"
+        value {
+          list {
+            type: DT_STRING
+          }
+        }
+      }
+      attr {
+        key: "summarize"
+        value {
+          i: 3
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/DecodeJpeg"
+      op: "DecodeJpeg"
+      input: "decode_image/cond_jpeg/DecodeJpeg/Switch:output_true:0"
+      input: "^decode_image/cond_jpeg/Assert/Assert"
+      attr {
+        key: "acceptable_fraction"
+        value {
+          f: 1.0
+        }
+      }
+      attr {
+        key: "channels"
+        value {
+          i: 3
+        }
+      }
+      attr {
+        key: "dct_method"
+        value {
+          s: ""
+        }
+      }
+      attr {
+        key: "fancy_upscaling"
+        value {
+          b: true
+        }
+      }
+      attr {
+        key: "ratio"
+        value {
+          i: 1
+        }
+      }
+      attr {
+        key: "try_recover_truncated"
+        value {
+          b: false
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/DecodeJpeg/Switch"
+      op: "Switch"
+      input: "Reshape:output:0"
+      input: "decode_image/cond_jpeg/pred_id:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "_class"
+        value {
+          list {
+            s: "loc:@Reshape"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/is_png/y"
+      op: "Const"
+      input: "^decode_image/cond_jpeg/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: "\211PN"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/is_png"
+      op: "Equal"
+      input: "decode_image/cond_jpeg/is_png/Switch:output_false:0"
+      input: "decode_image/cond_jpeg/is_png/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_STRING
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/is_png/Switch"
+      op: "Switch"
+      input: "decode_image/Substr:output:0"
+      input: "decode_image/cond_jpeg/pred_id:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "_class"
+        value {
+          list {
+            s: "loc:@decode_image/Substr"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/Switch"
+      op: "Switch"
+      input: "decode_image/cond_jpeg/is_png:z:0"
+      input: "decode_image/cond_jpeg/is_png:z:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/switch_t"
+      op: "Identity"
+      input: "decode_image/cond_jpeg/cond_png/Switch:output_true:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/switch_f"
+      op: "Identity"
+      input: "decode_image/cond_jpeg/cond_png/Switch:output_false:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/pred_id"
+      op: "Identity"
+      input: "decode_image/cond_jpeg/is_png:z:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/DecodePng"
+      op: "DecodePng"
+      input: "decode_image/cond_jpeg/cond_png/DecodePng/Switch_1:output_true:0"
+      attr {
+        key: "channels"
+        value {
+          i: 3
+        }
+      }
+      attr {
+        key: "dtype"
+        value {
+          type: DT_UINT8
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/DecodePng/Switch"
+      op: "Switch"
+      input: "Reshape:output:0"
+      input: "decode_image/cond_jpeg/pred_id:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "_class"
+        value {
+          list {
+            s: "loc:@Reshape"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/DecodePng/Switch_1"
+      op: "Switch"
+      input: "decode_image/cond_jpeg/cond_png/DecodePng/Switch:output_false:0"
+      input: "decode_image/cond_jpeg/cond_png/pred_id:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "_class"
+        value {
+          list {
+            s: "loc:@Reshape"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/is_gif/y"
+      op: "Const"
+      input: "^decode_image/cond_jpeg/cond_png/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: "GIF"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/is_gif"
+      op: "Equal"
+      input: "decode_image/cond_jpeg/cond_png/is_gif/Switch:output_false:0"
+      input: "decode_image/cond_jpeg/cond_png/is_gif/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_STRING
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/is_gif/Switch"
+      op: "Switch"
+      input: "decode_image/cond_jpeg/is_png/Switch:output_false:0"
+      input: "decode_image/cond_jpeg/cond_png/pred_id:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "_class"
+        value {
+          list {
+            s: "loc:@decode_image/Substr"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/Switch"
+      op: "Switch"
+      input: "decode_image/cond_jpeg/cond_png/is_gif:z:0"
+      input: "decode_image/cond_jpeg/cond_png/is_gif:z:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/switch_t"
+      op: "Identity"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/Switch:output_true:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/switch_f"
+      op: "Identity"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/Switch:output_false:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/pred_id"
+      op: "Identity"
+      input: "decode_image/cond_jpeg/cond_png/is_gif:z:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels/x"
+      op: "Const"
+      input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 3
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels/y"
+      op: "Const"
+      input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels"
+      op: "NotEqual"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels/x:output:0"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels_1/x"
+      op: "Const"
+      input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 3
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels_1/y"
+      op: "Const"
+      input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 4
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels_1"
+      op: "NotEqual"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels_1/x:output:0"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels_1/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/LogicalAnd"
+      op: "LogicalAnd"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels:z:0"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels_1:z:0"
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/Assert/Const"
+      op: "Const"
+      input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: "Channels must be in (None, 0, 3) when decoding GIF images"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/Assert/Assert/data_0"
+      op: "Const"
+      input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: "Channels must be in (None, 0, 3) when decoding GIF images"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/Assert/Assert"
+      op: "Assert"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/LogicalAnd:z:0"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/Assert/Assert/data_0:output:0"
+      attr {
+        key: "T"
+        value {
+          list {
+            type: DT_STRING
+          }
+        }
+      }
+      attr {
+        key: "summarize"
+        value {
+          i: 3
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/DecodeGif"
+      op: "DecodeGif"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/DecodeGif/Switch_1:output_true:0"
+      input: "^decode_image/cond_jpeg/cond_png/cond_gif/Assert/Assert"
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/DecodeGif/Switch"
+      op: "Switch"
+      input: "decode_image/cond_jpeg/cond_png/DecodePng/Switch:output_false:0"
+      input: "decode_image/cond_jpeg/cond_png/pred_id:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "_class"
+        value {
+          list {
+            s: "loc:@Reshape"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/DecodeGif/Switch_1"
+      op: "Switch"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/DecodeGif/Switch:output_false:0"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/pred_id:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "_class"
+        value {
+          list {
+            s: "loc:@Reshape"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/Substr/pos"
+      op: "Const"
+      input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/Substr/len"
+      op: "Const"
+      input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 2
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/Substr"
+      op: "Substr"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/Substr/Switch:output_false:0"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/Substr/pos:output:0"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/Substr/len:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/Substr/Switch"
+      op: "Switch"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/DecodeGif/Switch:output_false:0"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/pred_id:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "_class"
+        value {
+          list {
+            s: "loc:@Reshape"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/is_bmp/y"
+      op: "Const"
+      input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: "BM"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/is_bmp"
+      op: "Equal"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/Substr:output:0"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/is_bmp/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_STRING
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/Assert_1/Const"
+      op: "Const"
+      input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: "Unable to decode bytes as JPEG, PNG, GIF, or BMP"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/Assert_1/Assert/data_0"
+      op: "Const"
+      input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: "Unable to decode bytes as JPEG, PNG, GIF, or BMP"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/Assert_1/Assert"
+      op: "Assert"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/is_bmp:z:0"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/Assert_1/Assert/data_0:output:0"
+      attr {
+        key: "T"
+        value {
+          list {
+            type: DT_STRING
+          }
+        }
+      }
+      attr {
+        key: "summarize"
+        value {
+          i: 3
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/check_channels/x"
+      op: "Const"
+      input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 3
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/check_channels/y"
+      op: "Const"
+      input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/check_channels"
+      op: "NotEqual"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/check_channels/x:output:0"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/check_channels/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/Assert_2/Const"
+      op: "Const"
+      input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: "Channels must be in (None, 0, 3) when decoding BMP images"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/Assert_2/Assert/data_0"
+      op: "Const"
+      input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: "Channels must be in (None, 0, 3) when decoding BMP images"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/Assert_2/Assert"
+      op: "Assert"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/check_channels:z:0"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/Assert_2/Assert/data_0:output:0"
+      attr {
+        key: "T"
+        value {
+          list {
+            type: DT_STRING
+          }
+        }
+      }
+      attr {
+        key: "summarize"
+        value {
+          i: 3
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/DecodeBmp"
+      op: "DecodeBmp"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/Substr/Switch:output_false:0"
+      input: "^decode_image/cond_jpeg/cond_png/cond_gif/Assert_1/Assert"
+      input: "^decode_image/cond_jpeg/cond_png/cond_gif/Assert_2/Assert"
+      attr {
+        key: "channels"
+        value {
+          i: 0
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/cond_gif/Merge"
+      op: "Merge"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/DecodeBmp:image:0"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/DecodeGif:image:0"
+      attr {
+        key: "N"
+        value {
+          i: 2
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_UINT8
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/cond_png/Merge"
+      op: "Merge"
+      input: "decode_image/cond_jpeg/cond_png/cond_gif/Merge:output:0"
+      input: "decode_image/cond_jpeg/cond_png/DecodePng:image:0"
+      attr {
+        key: "N"
+        value {
+          i: 2
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_UINT8
+        }
+      }
+    }
+    node_def {
+      name: "decode_image/cond_jpeg/Merge"
+      op: "Merge"
+      input: "decode_image/cond_jpeg/cond_png/Merge:output:0"
+      input: "decode_image/cond_jpeg/DecodeJpeg:image:0"
+      attr {
+        key: "N"
+        value {
+          i: 2
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_UINT8
+        }
+      }
+    }
+    node_def {
+      name: "convert_image/Cast"
+      op: "Cast"
+      input: "decode_image/cond_jpeg/Merge:output:0"
+      attr {
+        key: "DstT"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "SrcT"
+        value {
+          type: DT_UINT8
+        }
+      }
+    }
+    node_def {
+      name: "convert_image/y"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_FLOAT
+            tensor_shape {
+            }
+            float_val: 0.00392156885937
+          }
+        }
+      }
+    }
+    node_def {
+      name: "convert_image"
+      op: "Mul"
+      input: "convert_image/Cast:y:0"
+      input: "convert_image/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+    }
+    node_def {
+      name: "Const"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_FLOAT
+            tensor_shape {
+              dim {
+                size: 1
+              }
+              dim {
+                size: 1
+              }
+              dim {
+                size: 4
+              }
+            }
+            tensor_content: "\000\000\000\000\000\000\000\000\000\000\200?\000\000\200?"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "distorted_bounding_box_crop/Shape"
+      op: "Shape"
+      input: "convert_image:z:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "out_type"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "distorted_bounding_box_crop/sample_distorted_bounding_box/SampleDistortedBoundingBoxV2/min_object_covered"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_FLOAT
+            tensor_shape {
+            }
+            float_val: 0.10000000149
+          }
+        }
+      }
+    }
+    node_def {
+      name: "distorted_bounding_box_crop/sample_distorted_bounding_box/SampleDistortedBoundingBoxV2"
+      op: "SampleDistortedBoundingBoxV2"
+      input: "distorted_bounding_box_crop/Shape:output:0"
+      input: "Const:output:0"
+      input: "distorted_bounding_box_crop/sample_distorted_bounding_box/SampleDistortedBoundingBoxV2/min_object_covered:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "area_range"
+        value {
+          list {
+            f: 0.0799999982119
+            f: 1.0
+          }
+        }
+      }
+      attr {
+        key: "aspect_ratio_range"
+        value {
+          list {
+            f: 0.75
+            f: 1.33333337307
+          }
+        }
+      }
+      attr {
+        key: "max_attempts"
+        value {
+          i: 1
+        }
+      }
+      attr {
+        key: "seed"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "seed2"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "use_image_if_no_bounding_boxes"
+        value {
+          b: true
+        }
+      }
+    }
+    node_def {
+      name: "distorted_bounding_box_crop/Slice"
+      op: "Slice"
+      input: "convert_image:z:0"
+      input: "distorted_bounding_box_crop/sample_distorted_bounding_box/SampleDistortedBoundingBoxV2:begin:0"
+      input: "distorted_bounding_box_crop/sample_distorted_bounding_box/SampleDistortedBoundingBoxV2:size:0"
+      attr {
+        key: "Index"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+    }
+    node_def {
+      name: "Shape"
+      op: "Shape"
+      input: "convert_image:z:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "out_type"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "Shape_1"
+      op: "Shape"
+      input: "distorted_bounding_box_crop/Slice:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "out_type"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "Equal"
+      op: "Equal"
+      input: "Shape:output:0"
+      input: "Shape_1:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "Cast"
+      op: "Cast"
+      input: "Equal:z:0"
+      attr {
+        key: "DstT"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "SrcT"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "Const_1"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "Sum"
+      op: "Sum"
+      input: "Cast:y:0"
+      input: "Const_1:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "Tidx"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "keep_dims"
+        value {
+          b: false
+        }
+      }
+    }
+    node_def {
+      name: "GreaterEqual/y"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 3
+          }
+        }
+      }
+    }
+    node_def {
+      name: "GreaterEqual"
+      op: "GreaterEqual"
+      input: "Sum:output:0"
+      input: "GreaterEqual/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "cond/Switch"
+      op: "Switch"
+      input: "GreaterEqual:z:0"
+      input: "GreaterEqual:z:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "cond/switch_t"
+      op: "Identity"
+      input: "cond/Switch:output_true:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "cond/switch_f"
+      op: "Identity"
+      input: "cond/Switch:output_false:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "cond/pred_id"
+      op: "Identity"
+      input: "GreaterEqual:z:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "cond/Shape"
+      op: "Shape"
+      input: "cond/Shape/Switch:output_true:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "out_type"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "cond/Shape/Switch"
+      op: "Switch"
+      input: "convert_image:z:0"
+      input: "cond/pred_id:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "_class"
+        value {
+          list {
+            s: "loc:@convert_image"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/Cast"
+      op: "Cast"
+      input: "cond/Shape:output:0"
+      attr {
+        key: "DstT"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "SrcT"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice/stack"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice/stack_1"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice/stack_2"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice"
+      op: "StridedSlice"
+      input: "cond/Cast:y:0"
+      input: "cond/strided_slice/stack:output:0"
+      input: "cond/strided_slice/stack_1:output:0"
+      input: "cond/strided_slice/stack_2:output:0"
+      attr {
+        key: "Index"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "begin_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "ellipsis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "end_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "new_axis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "shrink_axis_mask"
+        value {
+          i: 1
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_1/stack"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_1/stack_1"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 2
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_1/stack_2"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_1"
+      op: "StridedSlice"
+      input: "cond/Cast:y:0"
+      input: "cond/strided_slice_1/stack:output:0"
+      input: "cond/strided_slice_1/stack_1:output:0"
+      input: "cond/strided_slice_1/stack_2:output:0"
+      attr {
+        key: "Index"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "begin_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "ellipsis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "end_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "new_axis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "shrink_axis_mask"
+        value {
+          i: 1
+        }
+      }
+    }
+    node_def {
+      name: "cond/Greater"
+      op: "Greater"
+      input: "cond/strided_slice:output:0"
+      input: "cond/strided_slice_1:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/Switch"
+      op: "Switch"
+      input: "cond/Greater:z:0"
+      input: "cond/Greater:z:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/switch_t"
+      op: "Identity"
+      input: "cond/cond/Switch:output_true:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/switch_f"
+      op: "Identity"
+      input: "cond/cond/Switch:output_false:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/pred_id"
+      op: "Identity"
+      input: "cond/Greater:z:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/strided_slice/stack"
+      op: "Const"
+      input: "^cond/cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/strided_slice/stack_1"
+      op: "Const"
+      input: "^cond/cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/strided_slice/stack_2"
+      op: "Const"
+      input: "^cond/cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/strided_slice"
+      op: "StridedSlice"
+      input: "cond/cond/strided_slice/Switch:output_true:0"
+      input: "cond/cond/strided_slice/stack:output:0"
+      input: "cond/cond/strided_slice/stack_1:output:0"
+      input: "cond/cond/strided_slice/stack_2:output:0"
+      attr {
+        key: "Index"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "begin_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "ellipsis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "end_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "new_axis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "shrink_axis_mask"
+        value {
+          i: 1
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/strided_slice/Switch"
+      op: "Switch"
+      input: "cond/Cast:y:0"
+      input: "cond/cond/pred_id:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "_class"
+        value {
+          list {
+            s: "loc:@cond/Cast"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/strided_slice_1/stack"
+      op: "Const"
+      input: "^cond/cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/strided_slice_1/stack_1"
+      op: "Const"
+      input: "^cond/cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 2
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/strided_slice_1/stack_2"
+      op: "Const"
+      input: "^cond/cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/strided_slice_1"
+      op: "StridedSlice"
+      input: "cond/cond/strided_slice/Switch:output_true:0"
+      input: "cond/cond/strided_slice_1/stack:output:0"
+      input: "cond/cond/strided_slice_1/stack_1:output:0"
+      input: "cond/cond/strided_slice_1/stack_2:output:0"
+      attr {
+        key: "Index"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "begin_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "ellipsis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "end_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "new_axis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "shrink_axis_mask"
+        value {
+          i: 1
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/truediv"
+      op: "RealDiv"
+      input: "cond/cond/strided_slice:output:0"
+      input: "cond/cond/strided_slice_1:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/mul/y"
+      op: "Const"
+      input: "^cond/cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_FLOAT
+            tensor_shape {
+            }
+            float_val: 224.0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/mul"
+      op: "Mul"
+      input: "cond/cond/truediv:z:0"
+      input: "cond/cond/mul/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/Cast/x/1"
+      op: "Const"
+      input: "^cond/cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_FLOAT
+            tensor_shape {
+            }
+            float_val: 224.0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/Cast/x"
+      op: "Pack"
+      input: "cond/cond/mul:z:0"
+      input: "cond/cond/Cast/x/1:output:0"
+      attr {
+        key: "N"
+        value {
+          i: 2
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "axis"
+        value {
+          i: 0
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/Cast"
+      op: "Cast"
+      input: "cond/cond/Cast/x:output:0"
+      attr {
+        key: "DstT"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "SrcT"
+        value {
+          type: DT_FLOAT
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/strided_slice_2/stack"
+      op: "Const"
+      input: "^cond/cond/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/strided_slice_2/stack_1"
+      op: "Const"
+      input: "^cond/cond/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 2
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/strided_slice_2/stack_2"
+      op: "Const"
+      input: "^cond/cond/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/strided_slice_2"
+      op: "StridedSlice"
+      input: "cond/cond/strided_slice_2/Switch:output_false:0"
+      input: "cond/cond/strided_slice_2/stack:output:0"
+      input: "cond/cond/strided_slice_2/stack_1:output:0"
+      input: "cond/cond/strided_slice_2/stack_2:output:0"
+      attr {
+        key: "Index"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "begin_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "ellipsis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "end_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "new_axis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "shrink_axis_mask"
+        value {
+          i: 1
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/strided_slice_2/Switch"
+      op: "Switch"
+      input: "cond/Cast:y:0"
+      input: "cond/cond/pred_id:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "_class"
+        value {
+          list {
+            s: "loc:@cond/Cast"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/strided_slice_3/stack"
+      op: "Const"
+      input: "^cond/cond/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/strided_slice_3/stack_1"
+      op: "Const"
+      input: "^cond/cond/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/strided_slice_3/stack_2"
+      op: "Const"
+      input: "^cond/cond/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/strided_slice_3"
+      op: "StridedSlice"
+      input: "cond/cond/strided_slice_2/Switch:output_false:0"
+      input: "cond/cond/strided_slice_3/stack:output:0"
+      input: "cond/cond/strided_slice_3/stack_1:output:0"
+      input: "cond/cond/strided_slice_3/stack_2:output:0"
+      attr {
+        key: "Index"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "begin_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "ellipsis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "end_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "new_axis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "shrink_axis_mask"
+        value {
+          i: 1
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/truediv_1"
+      op: "RealDiv"
+      input: "cond/cond/strided_slice_2:output:0"
+      input: "cond/cond/strided_slice_3:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/mul_1/y"
+      op: "Const"
+      input: "^cond/cond/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_FLOAT
+            tensor_shape {
+            }
+            float_val: 224.0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/mul_1"
+      op: "Mul"
+      input: "cond/cond/truediv_1:z:0"
+      input: "cond/cond/mul_1/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/Cast_1/x/0"
+      op: "Const"
+      input: "^cond/cond/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_FLOAT
+            tensor_shape {
+            }
+            float_val: 224.0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/Cast_1/x"
+      op: "Pack"
+      input: "cond/cond/Cast_1/x/0:output:0"
+      input: "cond/cond/mul_1:z:0"
+      attr {
+        key: "N"
+        value {
+          i: 2
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "axis"
+        value {
+          i: 0
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/Cast_1"
+      op: "Cast"
+      input: "cond/cond/Cast_1/x:output:0"
+      attr {
+        key: "DstT"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "SrcT"
+        value {
+          type: DT_FLOAT
+        }
+      }
+    }
+    node_def {
+      name: "cond/cond/Merge"
+      op: "Merge"
+      input: "cond/cond/Cast_1:y:0"
+      input: "cond/cond/Cast:y:0"
+      attr {
+        key: "N"
+        value {
+          i: 2
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "cond/ResizeBicubic/images"
+      op: "Pack"
+      input: "cond/Shape/Switch:output_true:0"
+      attr {
+        key: "N"
+        value {
+          i: 1
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "axis"
+        value {
+          i: 0
+        }
+      }
+    }
+    node_def {
+      name: "cond/ResizeBicubic"
+      op: "ResizeBicubic"
+      input: "cond/ResizeBicubic/images:output:0"
+      input: "cond/cond/Merge:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "align_corners"
+        value {
+          b: false
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_2/stack"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_2/stack_1"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_2/stack_2"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_2"
+      op: "StridedSlice"
+      input: "cond/ResizeBicubic:resized_images:0"
+      input: "cond/strided_slice_2/stack:output:0"
+      input: "cond/strided_slice_2/stack_1:output:0"
+      input: "cond/strided_slice_2/stack_2:output:0"
+      attr {
+        key: "Index"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "begin_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "ellipsis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "end_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "new_axis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "shrink_axis_mask"
+        value {
+          i: 1
+        }
+      }
+    }
+    node_def {
+      name: "cond/Shape_1"
+      op: "Shape"
+      input: "cond/strided_slice_2:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "out_type"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_3/stack"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_3/stack_1"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_3/stack_2"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_3"
+      op: "StridedSlice"
+      input: "cond/Shape_1:output:0"
+      input: "cond/strided_slice_3/stack:output:0"
+      input: "cond/strided_slice_3/stack_1:output:0"
+      input: "cond/strided_slice_3/stack_2:output:0"
+      attr {
+        key: "Index"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "begin_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "ellipsis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "end_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "new_axis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "shrink_axis_mask"
+        value {
+          i: 1
+        }
+      }
+    }
+    node_def {
+      name: "cond/Shape_2"
+      op: "Shape"
+      input: "cond/strided_slice_2:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "out_type"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_4/stack"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_4/stack_1"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 2
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_4/stack_2"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_4"
+      op: "StridedSlice"
+      input: "cond/Shape_2:output:0"
+      input: "cond/strided_slice_4/stack:output:0"
+      input: "cond/strided_slice_4/stack_1:output:0"
+      input: "cond/strided_slice_4/stack_2:output:0"
+      attr {
+        key: "Index"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "begin_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "ellipsis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "end_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "new_axis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "shrink_axis_mask"
+        value {
+          i: 1
+        }
+      }
+    }
+    node_def {
+      name: "cond/sub/y"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 224
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/sub"
+      op: "Sub"
+      input: "cond/strided_slice_3:output:0"
+      input: "cond/sub/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "cond/add/y"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/add"
+      op: "Add"
+      input: "cond/sub:z:0"
+      input: "cond/add/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "cond/truediv/y"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 2
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/truediv/Cast"
+      op: "Cast"
+      input: "cond/add:z:0"
+      attr {
+        key: "DstT"
+        value {
+          type: DT_DOUBLE
+        }
+      }
+      attr {
+        key: "SrcT"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "cond/truediv/Cast_1"
+      op: "Cast"
+      input: "cond/truediv/y:output:0"
+      attr {
+        key: "DstT"
+        value {
+          type: DT_DOUBLE
+        }
+      }
+      attr {
+        key: "SrcT"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "cond/truediv"
+      op: "RealDiv"
+      input: "cond/truediv/Cast:y:0"
+      input: "cond/truediv/Cast_1:y:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_DOUBLE
+        }
+      }
+    }
+    node_def {
+      name: "cond/sub_1/y"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 224
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/sub_1"
+      op: "Sub"
+      input: "cond/strided_slice_4:output:0"
+      input: "cond/sub_1/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "cond/add_1/y"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/add_1"
+      op: "Add"
+      input: "cond/sub_1:z:0"
+      input: "cond/add_1/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "cond/truediv_1/y"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 2
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/truediv_1/Cast"
+      op: "Cast"
+      input: "cond/add_1:z:0"
+      attr {
+        key: "DstT"
+        value {
+          type: DT_DOUBLE
+        }
+      }
+      attr {
+        key: "SrcT"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "cond/truediv_1/Cast_1"
+      op: "Cast"
+      input: "cond/truediv_1/y:output:0"
+      attr {
+        key: "DstT"
+        value {
+          type: DT_DOUBLE
+        }
+      }
+      attr {
+        key: "SrcT"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "cond/truediv_1"
+      op: "RealDiv"
+      input: "cond/truediv_1/Cast:y:0"
+      input: "cond/truediv_1/Cast_1:y:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_DOUBLE
+        }
+      }
+    }
+    node_def {
+      name: "cond/Shape_3"
+      op: "Shape"
+      input: "cond/strided_slice_2:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "out_type"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "cond/Rank"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 3
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/Equal/y"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 3
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/Equal"
+      op: "Equal"
+      input: "cond/Rank:output:0"
+      input: "cond/Equal/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "cond/Assert/Const"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: "Rank of image must be equal to 3."
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/Assert/Assert/data_0"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: "Rank of image must be equal to 3."
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/Assert/Assert"
+      op: "Assert"
+      input: "cond/Equal:z:0"
+      input: "cond/Assert/Assert/data_0:output:0"
+      attr {
+        key: "T"
+        value {
+          list {
+            type: DT_STRING
+          }
+        }
+      }
+      attr {
+        key: "summarize"
+        value {
+          i: 3
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_5/stack"
+      op: "Const"
+      input: "^cond/Assert/Assert"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 2
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_5/stack_1"
+      op: "Const"
+      input: "^cond/Assert/Assert"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 3
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_5/stack_2"
+      op: "Const"
+      input: "^cond/Assert/Assert"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_5"
+      op: "StridedSlice"
+      input: "cond/Shape_3:output:0"
+      input: "cond/strided_slice_5/stack:output:0"
+      input: "cond/strided_slice_5/stack_1:output:0"
+      input: "cond/strided_slice_5/stack_2:output:0"
+      attr {
+        key: "Index"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "begin_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "ellipsis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "end_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "new_axis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "shrink_axis_mask"
+        value {
+          i: 1
+        }
+      }
+    }
+    node_def {
+      name: "cond/stack/0"
+      op: "Const"
+      input: "^cond/Assert/Assert"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 224
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/stack/1"
+      op: "Const"
+      input: "^cond/Assert/Assert"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 224
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/stack"
+      op: "Pack"
+      input: "cond/stack/0:output:0"
+      input: "cond/stack/1:output:0"
+      input: "cond/strided_slice_5:output:0"
+      attr {
+        key: "N"
+        value {
+          i: 3
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "axis"
+        value {
+          i: 0
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_6/stack"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_6/stack_1"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_6/stack_2"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_6"
+      op: "StridedSlice"
+      input: "cond/Shape_3:output:0"
+      input: "cond/strided_slice_6/stack:output:0"
+      input: "cond/strided_slice_6/stack_1:output:0"
+      input: "cond/strided_slice_6/stack_2:output:0"
+      attr {
+        key: "Index"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "begin_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "ellipsis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "end_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "new_axis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "shrink_axis_mask"
+        value {
+          i: 1
+        }
+      }
+    }
+    node_def {
+      name: "cond/GreaterEqual/y"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 224
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/GreaterEqual"
+      op: "GreaterEqual"
+      input: "cond/strided_slice_6:output:0"
+      input: "cond/GreaterEqual/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_7/stack"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_7/stack_1"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 2
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_7/stack_2"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_7"
+      op: "StridedSlice"
+      input: "cond/Shape_3:output:0"
+      input: "cond/strided_slice_7/stack:output:0"
+      input: "cond/strided_slice_7/stack_1:output:0"
+      input: "cond/strided_slice_7/stack_2:output:0"
+      attr {
+        key: "Index"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "begin_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "ellipsis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "end_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "new_axis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "shrink_axis_mask"
+        value {
+          i: 1
+        }
+      }
+    }
+    node_def {
+      name: "cond/GreaterEqual_1/y"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 224
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/GreaterEqual_1"
+      op: "GreaterEqual"
+      input: "cond/strided_slice_7:output:0"
+      input: "cond/GreaterEqual_1/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "cond/LogicalAnd"
+      op: "LogicalAnd"
+      input: "cond/GreaterEqual:z:0"
+      input: "cond/GreaterEqual_1:z:0"
+    }
+    node_def {
+      name: "cond/Assert_1/Const"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: "Crop size greater than the image size."
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/Assert_1/Assert/data_0"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: "Crop size greater than the image size."
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/Assert_1/Assert"
+      op: "Assert"
+      input: "cond/LogicalAnd:z:0"
+      input: "cond/Assert_1/Assert/data_0:output:0"
+      attr {
+        key: "T"
+        value {
+          list {
+            type: DT_STRING
+          }
+        }
+      }
+      attr {
+        key: "summarize"
+        value {
+          i: 3
+        }
+      }
+    }
+    node_def {
+      name: "cond/stack_1/2"
+      op: "Const"
+      input: "^cond/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_DOUBLE
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_DOUBLE
+            tensor_shape {
+            }
+            double_val: 0.0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/stack_1"
+      op: "Pack"
+      input: "cond/truediv:z:0"
+      input: "cond/truediv_1:z:0"
+      input: "cond/stack_1/2:output:0"
+      attr {
+        key: "N"
+        value {
+          i: 3
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_DOUBLE
+        }
+      }
+      attr {
+        key: "axis"
+        value {
+          i: 0
+        }
+      }
+    }
+    node_def {
+      name: "cond/ToInt32"
+      op: "Cast"
+      input: "cond/stack_1:output:0"
+      attr {
+        key: "DstT"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "SrcT"
+        value {
+          type: DT_DOUBLE
+        }
+      }
+    }
+    node_def {
+      name: "cond/Slice"
+      op: "Slice"
+      input: "cond/strided_slice_2:output:0"
+      input: "cond/ToInt32:y:0"
+      input: "cond/stack:output:0"
+      input: "^cond/Assert_1/Assert"
+      attr {
+        key: "Index"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+    }
+    node_def {
+      name: "cond/Reshape"
+      op: "Reshape"
+      input: "cond/Slice:output:0"
+      input: "cond/stack:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "Tshape"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "cond/ResizeBicubic_1/images"
+      op: "Pack"
+      input: "cond/ResizeBicubic_1/images/Switch:output_false:0"
+      attr {
+        key: "N"
+        value {
+          i: 1
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "axis"
+        value {
+          i: 0
+        }
+      }
+    }
+    node_def {
+      name: "cond/ResizeBicubic_1/images/Switch"
+      op: "Switch"
+      input: "distorted_bounding_box_crop/Slice:output:0"
+      input: "cond/pred_id:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "_class"
+        value {
+          list {
+            s: "loc:@distorted_bounding_box_crop/Slice"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/ResizeBicubic_1/size"
+      op: "Const"
+      input: "^cond/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 2
+              }
+            }
+            tensor_content: "\340\000\000\000\340\000\000\000"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/ResizeBicubic_1"
+      op: "ResizeBicubic"
+      input: "cond/ResizeBicubic_1/images:output:0"
+      input: "cond/ResizeBicubic_1/size:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "align_corners"
+        value {
+          b: false
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_8/stack"
+      op: "Const"
+      input: "^cond/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_8/stack_1"
+      op: "Const"
+      input: "^cond/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_8/stack_2"
+      op: "Const"
+      input: "^cond/switch_f"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "cond/strided_slice_8"
+      op: "StridedSlice"
+      input: "cond/ResizeBicubic_1:resized_images:0"
+      input: "cond/strided_slice_8/stack:output:0"
+      input: "cond/strided_slice_8/stack_1:output:0"
+      input: "cond/strided_slice_8/stack_2:output:0"
+      attr {
+        key: "Index"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "begin_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "ellipsis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "end_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "new_axis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "shrink_axis_mask"
+        value {
+          i: 1
+        }
+      }
+    }
+    node_def {
+      name: "cond/Merge"
+      op: "Merge"
+      input: "cond/strided_slice_8:output:0"
+      input: "cond/Reshape:output:0"
+      attr {
+        key: "N"
+        value {
+          i: 2
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+    }
+    node_def {
+      name: "Const_2"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_FLOAT
+            tensor_shape {
+              dim {
+                size: 1
+              }
+              dim {
+                size: 1
+              }
+              dim {
+                size: 3
+              }
+            }
+            tensor_content: "\354Q\370>\325x\351>;\337\317>"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "sub"
+      op: "Sub"
+      input: "cond/Merge:output:0"
+      input: "Const_2:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+    }
+    node_def {
+      name: "Const_3"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_FLOAT
+            tensor_shape {
+              dim {
+                size: 1
+              }
+              dim {
+                size: 1
+              }
+              dim {
+                size: 3
+              }
+            }
+            tensor_content: "\372~j>B`e>fff>"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "truediv"
+      op: "RealDiv"
+      input: "sub:z:0"
+      input: "Const_3:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+    }
+    node_def {
+      name: "random_flip_left_right/control_dependency"
+      op: "Identity"
+      input: "truediv:z:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "_class"
+        value {
+          list {
+            s: "loc:@truediv"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "random_flip_left_right/random_uniform/shape"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+              }
+            }
+          }
+        }
+      }
+    }
+    node_def {
+      name: "random_flip_left_right/random_uniform/min"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_FLOAT
+            tensor_shape {
+            }
+            float_val: 0.0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "random_flip_left_right/random_uniform/max"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_FLOAT
+            tensor_shape {
+            }
+            float_val: 1.0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "random_flip_left_right/random_uniform/RandomUniform"
+      op: "RandomUniform"
+      input: "random_flip_left_right/random_uniform/shape:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "dtype"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "seed"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "seed2"
+        value {
+          i: 0
+        }
+      }
+    }
+    node_def {
+      name: "random_flip_left_right/random_uniform/sub"
+      op: "Sub"
+      input: "random_flip_left_right/random_uniform/max:output:0"
+      input: "random_flip_left_right/random_uniform/min:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+    }
+    node_def {
+      name: "random_flip_left_right/random_uniform/mul"
+      op: "Mul"
+      input: "random_flip_left_right/random_uniform/RandomUniform:output:0"
+      input: "random_flip_left_right/random_uniform/sub:z:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+    }
+    node_def {
+      name: "random_flip_left_right/random_uniform"
+      op: "Add"
+      input: "random_flip_left_right/random_uniform/mul:z:0"
+      input: "random_flip_left_right/random_uniform/min:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+    }
+    node_def {
+      name: "random_flip_left_right/Less/y"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_FLOAT
+            tensor_shape {
+            }
+            float_val: 0.5
+          }
+        }
+      }
+    }
+    node_def {
+      name: "random_flip_left_right/Less"
+      op: "Less"
+      input: "random_flip_left_right/random_uniform:z:0"
+      input: "random_flip_left_right/Less/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+    }
+    node_def {
+      name: "random_flip_left_right/Switch"
+      op: "Switch"
+      input: "random_flip_left_right/Less:z:0"
+      input: "random_flip_left_right/Less:z:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "random_flip_left_right/switch_t"
+      op: "Identity"
+      input: "random_flip_left_right/Switch:output_true:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "random_flip_left_right/switch_f"
+      op: "Identity"
+      input: "random_flip_left_right/Switch:output_false:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "random_flip_left_right/pred_id"
+      op: "Identity"
+      input: "random_flip_left_right/Less:z:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_BOOL
+        }
+      }
+    }
+    node_def {
+      name: "random_flip_left_right/ReverseV2/axis"
+      op: "Const"
+      input: "^random_flip_left_right/switch_t"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "random_flip_left_right/ReverseV2"
+      op: "ReverseV2"
+      input: "random_flip_left_right/ReverseV2/Switch:output_true:0"
+      input: "random_flip_left_right/ReverseV2/axis:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "Tidx"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "random_flip_left_right/ReverseV2/Switch"
+      op: "Switch"
+      input: "random_flip_left_right/control_dependency:output:0"
+      input: "random_flip_left_right/pred_id:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "_class"
+        value {
+          list {
+            s: "loc:@truediv"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "random_flip_left_right/Switch_1"
+      op: "Switch"
+      input: "random_flip_left_right/control_dependency:output:0"
+      input: "random_flip_left_right/pred_id:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "_class"
+        value {
+          list {
+            s: "loc:@truediv"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "random_flip_left_right/Merge"
+      op: "Merge"
+      input: "random_flip_left_right/Switch_1:output_false:0"
+      input: "random_flip_left_right/ReverseV2:output:0"
+      attr {
+        key: "N"
+        value {
+          i: 2
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+    }
+    node_def {
+      name: "Reshape_1/shape"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 3
+              }
+            }
+            tensor_content: "\340\000\000\000\340\000\000\000\003\000\000\000"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "Reshape_1"
+      op: "Reshape"
+      input: "random_flip_left_right/Merge:output:0"
+      input: "Reshape_1/shape:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "Tshape"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "Reshape_2/shape"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+              }
+            }
+          }
+        }
+      }
+    }
+    node_def {
+      name: "Reshape_2"
+      op: "Reshape"
+      input: "ParseSingleExample/ParseSingleExample:dense_values:0"
+      input: "Reshape_2/shape:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "Tshape"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    node_def {
+      name: "Cast_1"
+      op: "Cast"
+      input: "Reshape_2:output:0"
+      attr {
+        key: "DstT"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "SrcT"
+        value {
+          type: DT_INT64
+        }
+      }
+    }
+    node_def {
+      name: "sub_1/y"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "sub_1"
+      op: "Sub"
+      input: "Cast_1:y:0"
+      input: "sub_1/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT32
+        }
+      }
+    }
+    ret {
+      key: "Reshape_1"
+      value: "Reshape_1:output:0"
+    }
+    ret {
+      key: "sub_1"
+      value: "sub_1:z:0"
+    }
+  }
+  function {
+    signature {
+      name: "tf_predicate_7089b845"
+      input_arg {
+        name: "arg0"
+        type: DT_FLOAT
+      }
+      input_arg {
+        name: "arg1"
+        type: DT_INT32
+      }
+      input_arg {
+        name: "Equal/Placeholder"
+        type: DT_INT64
+      }
+      output_arg {
+        name: "Equal"
+        type: DT_BOOL
+      }
+      description: "A wrapper for Defun that facilitates shape inference."
+    }
+    node_def {
+      name: "Shape"
+      op: "Shape"
+      input: "arg0"
+      attr {
+        key: "T"
+        value {
+          type: DT_FLOAT
+        }
+      }
+      attr {
+        key: "out_type"
+        value {
+          type: DT_INT64
+        }
+      }
+    }
+    node_def {
+      name: "strided_slice/stack"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "strided_slice/stack_1"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "strided_slice/stack_2"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "strided_slice"
+      op: "StridedSlice"
+      input: "Shape:output:0"
+      input: "strided_slice/stack:output:0"
+      input: "strided_slice/stack_1:output:0"
+      input: "strided_slice/stack_2:output:0"
+      attr {
+        key: "Index"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "begin_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "ellipsis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "end_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "new_axis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "shrink_axis_mask"
+        value {
+          i: 1
+        }
+      }
+    }
+    node_def {
+      name: "Equal"
+      op: "Equal"
+      input: "strided_slice:output:0"
+      input: "Equal/Placeholder"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT64
+        }
+      }
+    }
+    ret {
+      key: "Equal"
+      value: "Equal:z:0"
+    }
+  }
+  function {
+    signature {
+      name: "_make_dataset_5fa5e1f4"
+      output_arg {
+        name: "PrefetchDataset_1"
+        type: DT_VARIANT
+      }
+      is_stateful: true
+    }
+    node_def {
+      name: "TensorSliceDataset/MatchingFiles/pattern"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: "$(DATA_DIR)"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "TensorSliceDataset/MatchingFiles"
+      op: "MatchingFiles"
+      input: "TensorSliceDataset/MatchingFiles/pattern:output:0"
+    }
+    node_def {
+      name: "TensorSliceDataset"
+      op: "TensorSliceDataset"
+      input: "TensorSliceDataset/MatchingFiles:filenames:0"
+      attr {
+        key: "Toutput_types"
+        value {
+          list {
+            type: DT_STRING
+          }
+        }
+      }
+      attr {
+        key: "output_shapes"
+        value {
+          list {
+            shape {
+            }
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ShuffleDataset/MatchingFiles/pattern"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_STRING
+            tensor_shape {
+            }
+            string_val: "$(DATA_DIR)"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ShuffleDataset/MatchingFiles"
+      op: "MatchingFiles"
+      input: "ShuffleDataset/MatchingFiles/pattern:output:0"
+    }
+    node_def {
+      name: "ShuffleDataset/Shape"
+      op: "Shape"
+      input: "ShuffleDataset/MatchingFiles:filenames:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_STRING
+        }
+      }
+      attr {
+        key: "out_type"
+        value {
+          type: DT_INT64
+        }
+      }
+    }
+    node_def {
+      name: "ShuffleDataset/strided_slice/stack"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ShuffleDataset/strided_slice/stack_1"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ShuffleDataset/strided_slice/stack_2"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+              dim {
+                size: 1
+              }
+            }
+            int_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ShuffleDataset/strided_slice"
+      op: "StridedSlice"
+      input: "ShuffleDataset/Shape:output:0"
+      input: "ShuffleDataset/strided_slice/stack:output:0"
+      input: "ShuffleDataset/strided_slice/stack_1:output:0"
+      input: "ShuffleDataset/strided_slice/stack_2:output:0"
+      attr {
+        key: "Index"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "T"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "begin_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "ellipsis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "end_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "new_axis_mask"
+        value {
+          i: 0
+        }
+      }
+      attr {
+        key: "shrink_axis_mask"
+        value {
+          i: 1
+        }
+      }
+    }
+    node_def {
+      name: "ShuffleDataset/Maximum/y"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT64
+            tensor_shape {
+            }
+            int64_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ShuffleDataset/Maximum"
+      op: "Maximum"
+      input: "ShuffleDataset/strided_slice:output:0"
+      input: "ShuffleDataset/Maximum/y:output:0"
+      attr {
+        key: "T"
+        value {
+          type: DT_INT64
+        }
+      }
+    }
+    node_def {
+      name: "ShuffleDataset/seed"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT64
+            tensor_shape {
+            }
+            int64_val: 0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ShuffleDataset/seed2"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT64
+            tensor_shape {
+            }
+            int64_val: 0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ShuffleDataset"
+      op: "ShuffleDataset"
+      input: "TensorSliceDataset:handle:0"
+      input: "ShuffleDataset/Maximum:z:0"
+      input: "ShuffleDataset/seed:output:0"
+      input: "ShuffleDataset/seed2:output:0"
+      attr {
+        key: "output_shapes"
+        value {
+          list {
+            shape {
+            }
+          }
+        }
+      }
+      attr {
+        key: "output_types"
+        value {
+          list {
+            type: DT_STRING
+          }
+        }
+      }
+      attr {
+        key: "reshuffle_each_iteration"
+        value {
+          b: true
+        }
+      }
+    }
+    node_def {
+      name: "ShuffleDataset_1/buffer_size"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT64
+            tensor_shape {
+            }
+            int64_val: 1024
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ShuffleDataset_1/seed_1"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT64
+            tensor_shape {
+            }
+            int64_val: 0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ShuffleDataset_1/seed2_1"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT64
+            tensor_shape {
+            }
+            int64_val: 0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ShuffleDataset_1"
+      op: "ShuffleDataset"
+      input: "ShuffleDataset:handle:0"
+      input: "ShuffleDataset_1/buffer_size:output:0"
+      input: "ShuffleDataset_1/seed_1:output:0"
+      input: "ShuffleDataset_1/seed2_1:output:0"
+      attr {
+        key: "output_shapes"
+        value {
+          list {
+            shape {
+            }
+          }
+        }
+      }
+      attr {
+        key: "output_types"
+        value {
+          list {
+            type: DT_STRING
+          }
+        }
+      }
+      attr {
+        key: "reshuffle_each_iteration"
+        value {
+          b: true
+        }
+      }
+    }
+    node_def {
+      name: "RepeatDataset/count"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT64
+            tensor_shape {
+            }
+            int64_val: -1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "RepeatDataset"
+      op: "RepeatDataset"
+      input: "ShuffleDataset_1:handle:0"
+      input: "RepeatDataset/count:output:0"
+      attr {
+        key: "output_shapes"
+        value {
+          list {
+            shape {
+            }
+          }
+        }
+      }
+      attr {
+        key: "output_types"
+        value {
+          list {
+            type: DT_STRING
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ParallelInterleaveDataset/cycle_length"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT64
+            tensor_shape {
+            }
+            int64_val: 8
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ParallelInterleaveDataset/block_length"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT64
+            tensor_shape {
+            }
+            int64_val: 1
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ParallelInterleaveDataset/sloppy"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_BOOL
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_BOOL
+            tensor_shape {
+            }
+            bool_val: true
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ParallelInterleaveDataset/buffer_output_elements"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT64
+            tensor_shape {
+            }
+            int64_val: 2
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ParallelInterleaveDataset/prefetch_input_elements"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT64
+            tensor_shape {
+            }
+            int64_val: 16
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ParallelInterleaveDataset"
+      op: "ParallelInterleaveDataset"
+      input: "RepeatDataset:handle:0"
+      input: "ParallelInterleaveDataset/cycle_length:output:0"
+      input: "ParallelInterleaveDataset/block_length:output:0"
+      input: "ParallelInterleaveDataset/sloppy:output:0"
+      input: "ParallelInterleaveDataset/buffer_output_elements:output:0"
+      input: "ParallelInterleaveDataset/prefetch_input_elements:output:0"
+      attr {
+        key: "Targuments"
+        value {
+          list {
+          }
+        }
+      }
+      attr {
+        key: "f"
+        value {
+          func {
+            name: "tf_map_func_91295dea"
+          }
+        }
+      }
+      attr {
+        key: "output_shapes"
+        value {
+          list {
+            shape {
+            }
+          }
+        }
+      }
+      attr {
+        key: "output_types"
+        value {
+          list {
+            type: DT_STRING
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ShuffleDataset_2/buffer_size_1"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT64
+            tensor_shape {
+            }
+            int64_val: 1024
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ShuffleDataset_2/seed_2"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT64
+            tensor_shape {
+            }
+            int64_val: 0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ShuffleDataset_2/seed2_2"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT64
+            tensor_shape {
+            }
+            int64_val: 0
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ShuffleDataset_2"
+      op: "ShuffleDataset"
+      input: "ParallelInterleaveDataset:handle:0"
+      input: "ShuffleDataset_2/buffer_size_1:output:0"
+      input: "ShuffleDataset_2/seed_2:output:0"
+      input: "ShuffleDataset_2/seed2_2:output:0"
+      attr {
+        key: "output_shapes"
+        value {
+          list {
+            shape {
+            }
+          }
+        }
+      }
+      attr {
+        key: "output_types"
+        value {
+          list {
+            type: DT_STRING
+          }
+        }
+      }
+      attr {
+        key: "reshuffle_each_iteration"
+        value {
+          b: true
+        }
+      }
+    }
+    node_def {
+      name: "ParallelMapDataset/num_parallel_calls"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT32
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT32
+            tensor_shape {
+            }
+            int_val: 64
+          }
+        }
+      }
+    }
+    node_def {
+      name: "ParallelMapDataset"
+      op: "ParallelMapDataset"
+      input: "ShuffleDataset_2:handle:0"
+      input: "ParallelMapDataset/num_parallel_calls:output:0"
+      attr {
+        key: "Targuments"
+        value {
+          list {
+          }
+        }
+      }
+      attr {
+        key: "f"
+        value {
+          func {
+            name: "tf_map_func_74b6b15c"
+          }
+        }
+      }
+      attr {
+        key: "output_shapes"
+        value {
+          list {
+            shape {
+              dim {
+                size: 224
+              }
+              dim {
+                size: 224
+              }
+              dim {
+                size: 3
+              }
+            }
+            shape {
+            }
+          }
+        }
+      }
+      attr {
+        key: "output_types"
+        value {
+          list {
+            type: DT_FLOAT
+            type: DT_INT32
+          }
+        }
+      }
+    }
+    node_def {
+      name: "PrefetchDataset/buffer_size_2"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT64
+            tensor_shape {
+            }
+            int64_val: 64
+          }
+        }
+      }
+    }
+    node_def {
+      name: "PrefetchDataset"
+      op: "PrefetchDataset"
+      input: "ParallelMapDataset:handle:0"
+      input: "PrefetchDataset/buffer_size_2:output:0"
+      attr {
+        key: "output_shapes"
+        value {
+          list {
+            shape {
+              dim {
+                size: 224
+              }
+              dim {
+                size: 224
+              }
+              dim {
+                size: 3
+              }
+            }
+            shape {
+            }
+          }
+        }
+      }
+      attr {
+        key: "output_types"
+        value {
+          list {
+            type: DT_FLOAT
+            type: DT_INT32
+          }
+        }
+      }
+    }
+    node_def {
+      name: "BatchDataset/batch_size"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT64
+            tensor_shape {
+            }
+            int64_val: 64
+          }
+        }
+      }
+    }
+    node_def {
+      name: "BatchDataset"
+      op: "BatchDataset"
+      input: "PrefetchDataset:handle:0"
+      input: "BatchDataset/batch_size:output:0"
+      attr {
+        key: "output_shapes"
+        value {
+          list {
+            shape {
+              dim {
+                size: -1
+              }
+              dim {
+                size: 224
+              }
+              dim {
+                size: 224
+              }
+              dim {
+                size: 3
+              }
+            }
+            shape {
+              dim {
+                size: -1
+              }
+            }
+          }
+        }
+      }
+      attr {
+        key: "output_types"
+        value {
+          list {
+            type: DT_FLOAT
+            type: DT_INT32
+          }
+        }
+      }
+    }
+    node_def {
+      name: "FilterDataset/batch_size_1"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT64
+            tensor_shape {
+            }
+            int64_val: 64
+          }
+        }
+      }
+    }
+    node_def {
+      name: "FilterDataset"
+      op: "FilterDataset"
+      input: "BatchDataset:handle:0"
+      input: "FilterDataset/batch_size_1:output:0"
+      attr {
+        key: "Targuments"
+        value {
+          list {
+            type: DT_INT64
+          }
+        }
+      }
+      attr {
+        key: "output_shapes"
+        value {
+          list {
+            shape {
+              dim {
+                size: -1
+              }
+              dim {
+                size: 224
+              }
+              dim {
+                size: 224
+              }
+              dim {
+                size: 3
+              }
+            }
+            shape {
+              dim {
+                size: -1
+              }
+            }
+          }
+        }
+      }
+      attr {
+        key: "output_types"
+        value {
+          list {
+            type: DT_FLOAT
+            type: DT_INT32
+          }
+        }
+      }
+      attr {
+        key: "predicate"
+        value {
+          func {
+            name: "tf_predicate_7089b845"
+          }
+        }
+      }
+    }
+    node_def {
+      name: "PrefetchDataset_1/buffer_size_3"
+      op: "Const"
+      attr {
+        key: "dtype"
+        value {
+          type: DT_INT64
+        }
+      }
+      attr {
+        key: "value"
+        value {
+          tensor {
+            dtype: DT_INT64
+            tensor_shape {
+            }
+            int64_val: 2
+          }
+        }
+      }
+    }
+    node_def {
+      name: "PrefetchDataset_1"
+      op: "PrefetchDataset"
+      input: "FilterDataset:handle:0"
+      input: "PrefetchDataset_1/buffer_size_3:output:0"
+      attr {
+        key: "output_shapes"
+        value {
+          list {
+            shape {
+              dim {
+                size: 64
+              }
+              dim {
+                size: 224
+              }
+              dim {
+                size: 224
+              }
+              dim {
+                size: 3
+              }
+            }
+            shape {
+              dim {
+                size: 64
+              }
+            }
+          }
+        }
+      }
+      attr {
+        key: "output_types"
+        value {
+          list {
+            type: DT_FLOAT
+            type: DT_INT32
+          }
+        }
+      }
+    }
+    ret {
+      key: "PrefetchDataset_1"
+      value: "PrefetchDataset_1:handle:0"
+    }
+  }
+}
+)PREFIX";
+
+  *dataset_name = "_make_dataset_5fa5e1f4";
+  std::function<void(FunctionDef*)> mutate_proto_func =
+      [dataset_name, file_path](FunctionDef* fdef) {
+        VLOG(1) << "Processsing function " << fdef->DebugString();
+        if (std::string(fdef->signature().name()) != *dataset_name) return;
+        // Change the input file pattern to `file_path`.
+        bool found = false;
+        for (auto& node_def : *fdef->mutable_node_def()) {
+          if (node_def.name() != "TensorSliceDataset/MatchingFiles/pattern" &&
+              node_def.name() != "ShuffleDataset/MatchingFiles/pattern")
+            continue;
+          DCHECK_EQ(node_def.op(), "Const");
+          DCHECK_GT(node_def.attr().count("value"), 0);
+          found = true;
+          DCHECK_EQ(node_def.attr().at("value").tensor().string_val(0),
+                    "$(DATA_DIR)");
+          VLOG(1) << "Setting the value of node_def "
+                     "TensorSliceDataset/MatchingFiles/pattern to "
+                  << file_path;
+          auto* tensor = (*node_def.mutable_attr())["value"].mutable_tensor();
+          tensor->clear_string_val();
+          tensor->add_string_val(file_path);
+        }
+        VLOG(1) << "Rewrote function to " << fdef->DebugString();
+        DCHECK(found);
+      };
+  return CreateFunctionsFromTextProto(func_def, &mutate_proto_func, status);
+}
+
+// Adds the input functions to `graph`.  On success, returns the created
+// IteratorGetNext node.
+static TF_Operation* AddDatasetFunctionAndIteratorNodesToGraph(
+    const std::vector<UniqueFuncPtr>& funcs, const std::string& dataset_name,
+    const std::vector<tensorflow::DataType>& output_types,
+    const std::vector<tensorflow::TensorShapeProto>& output_shapes,
+    TF_Graph* graph, TF_Status* status) {
+  DCHECK(!dataset_name.empty());
+  for (auto& func : funcs) {
+    TF_GraphCopyFunction(graph, func.get(), /*gradient*/ nullptr, status);
+    if (!status->status.ok()) {
+      return nullptr;
+    }
+  }
+
+  tensorflow::mutex_lock c(graph->mu);
+
+  tensorflow::NameAttrList func;
+  func.set_name(dataset_name);
+  // Run the iterator node on CPU.
+  Node* oneshot_iterator_node;
+  tensorflow::Status s = NodeBuilder("OneShotIterator", "OneShotIterator")
+                             .Device("/device:CPU:0")
+                             .Attr("container", "")
+                             .Attr("dataset_factory", func)
+                             .Attr("output_types", output_types)
+                             .Attr("output_shapes", output_shapes)
+                             .Attr("shared_name", "")
+                             .Finalize(&graph->graph, &oneshot_iterator_node);
+  if (!s.ok()) {
+    status->status = s;
+    return nullptr;
+  }
+  // Run shape inference function for each newly added node, so that more
+  // subsequent nodes can be added to the graph via C API (TF_NewOperation()).
+  s = graph->refiner.AddNode(oneshot_iterator_node);
+  if (!s.ok()) {
+    status->status = s;
+    return nullptr;
+  }
+
+  // Run the iterator node on CPU.
+  Node* getnext_node;
+  s = NodeBuilder("IteratorGetNext", "IteratorGetNext")
+          .Input(oneshot_iterator_node)
+          .Device("/device:CPU:0")
+          .Attr("output_types", output_types)
+          .Attr("output_shapes", output_shapes)
+          .Finalize(&graph->graph, &getnext_node);
+  if (!s.ok()) {
+    status->status = s;
+    return nullptr;
+  }
+  // Run shape inference function for each newly added node, so that more
+  // subsequent nodes can be added to the graph via C API (TF_NewOperation()).
+  s = graph->refiner.AddNode(getnext_node);
+  if (!s.ok()) {
+    status->status = s;
+    return nullptr;
+  }
+
+  VLOG(1) << "Output graph: " << graph->graph.ToGraphDefDebug().DebugString();
+  return ToTF_Operation(getnext_node);
+}
+
+TF_Operation* TF_MakeFakeIteratorGetNextWithDatasets(TF_Graph* graph,
+                                                     TF_Status* status) {
+  tensorflow::Status s;
+
+  std::string dataset_name;
+  UniqueFuncPtr result_func = CreateFakeDatasetFunction(&dataset_name, status);
+  if (!status->status.ok()) {
+    return nullptr;
+  }
+
+  std::vector<UniqueFuncPtr> funcs;
+  funcs.push_back(std::move(result_func));
+  std::vector<tensorflow::TensorShapeProto> output_shape_list;
+  output_shape_list.push_back(tensorflow::TensorShapeProto());
+  auto* getnext_node = AddDatasetFunctionAndIteratorNodesToGraph(
+      funcs, dataset_name, {tensorflow::DT_FLOAT}, output_shape_list, graph,
+      status);
+  if (!status->status.ok()) {
+    return nullptr;
+  }
+
+  return getnext_node;
+}
+
+TF_Operation* TF_MakeImagenetIteratorGetNextWithDatasets(TF_Graph* graph,
+                                                         const char* file_path,
+                                                         int batch_size,
+                                                         TF_Status* status) {
+  tensorflow::Status s;
+
+  std::string dataset_name;
+  const auto& funcs =
+      CreateImagenetDatasetFunctions(file_path, &dataset_name, status);
+  if (!status->status.ok()) {
+    return nullptr;
+  }
+
+  std::vector<tensorflow::TensorShapeProto> output_shape_list;
+  // batch_size X 224 X 224 X 3
+  auto image_shape = tensorflow::TensorShapeProto();
+  image_shape.add_dim()->set_size(batch_size);
+  image_shape.add_dim()->set_size(224);
+  image_shape.add_dim()->set_size(224);
+  image_shape.add_dim()->set_size(3);
+  output_shape_list.push_back(image_shape);
+
+  // batch_size
+  auto label_shape = tensorflow::TensorShapeProto();
+  label_shape.add_dim()->set_size(batch_size);
+  output_shape_list.push_back(label_shape);
+  auto* getnext_node = AddDatasetFunctionAndIteratorNodesToGraph(
+      funcs, dataset_name, {tensorflow::DT_FLOAT, tensorflow::DT_INT32},
+      output_shape_list, graph, status);
+  if (!status->status.ok()) {
+    return nullptr;
+  }
+
+  tensorflow::mutex_lock c(graph->mu);
+  VLOG(1) << "The extended graph: "
+          << graph->graph.ToGraphDefDebug().DebugString();
 
-  VLOG(1) << "Output graph: " << graph->graph.ToGraphDefDebug().DebugString();
-  *dataset_func = result_func.release();
-  return ToTF_Operation(getnext_node);
-}
-
-void TF_GetAttrScalarTensorShapeProto(TF_Buffer* value, TF_Status* status) {
-  status->status = Status::OK();
-  auto shape = tensorflow::TensorShape({});
-  tensorflow::TensorShapeProto shape_proto;
-  shape.AsProto(&shape_proto);
-  status->status = MessageToBuffer(shape_proto, value);
+  return getnext_node;
 }
index 2fa2328..a9c551d 100644 (file)
@@ -87,25 +87,22 @@ TF_CAPI_EXPORT extern const char* TF_GraphDebugString(TF_Graph* graph,
 TF_CAPI_EXPORT extern const char* TF_GraphDebugString(TF_Graph* graph,
                                                       size_t* len);
 
-// Creates a stack of data set + iterator nodes reading the TFRecord files from
-// `file_path`, and outputs the following info on success:
+// Creates a stack of data set + iterator nodes, currently hard-coded to return
+// a sequence of 3 float values <42.0, 43.0, 44.0> over 3 calls. On success,
+// returns the IteratorGetNext node, which caller can run or feed into an node.
 //
-// 1. Returns the IteratorGetNext node, which caller can run or feed into an
-// node.
-//
-// 2. Sets `dataset_func` to the created function that encapsulates the data set
-// nodes. Caller owns that function, and must call TF_DeleteFunction() on it.
-//
-//
-// The nodes are currently hard-coded to return a single Int32 of value 1.
 // TODO(hongm): Extend the API to allow customization of the nodes created.
-TF_CAPI_EXPORT extern TF_Operation* TF_MakeIteratorGetNextWithDatasets(
-    TF_Graph* graph, const char* file_path, TF_Function** dataset_func,
-    TF_Status* status);
-
-// Returns the shape proto of shape {}.
-TF_CAPI_EXPORT extern void TF_GetAttrScalarTensorShapeProto(TF_Buffer* value,
-                                                            TF_Status* status);
+TF_CAPI_EXPORT extern TF_Operation* TF_MakeFakeIteratorGetNextWithDatasets(
+    TF_Graph* graph, TF_Status* status);
+
+// Similar to the above API, except that the returned iterator reads the
+// TFRecord files from `file_path`.
+// The iterators outputs 2 tensors:
+// - A float tensor of shape `batch_size` X 224 X 224 X 3
+// - An int32 tensor of shape `batch_size`
+// TODO(hongm): Extend the API to allow customization of the nodes created.
+TF_CAPI_EXPORT extern TF_Operation* TF_MakeImagenetIteratorGetNextWithDatasets(
+    TF_Graph* graph, const char* file_path, int batch_size, TF_Status* status);
 
 #ifdef __cplusplus
 } /* end extern "C" */
index 9ddd65f..49d64d1 100644 (file)
@@ -15,38 +15,36 @@ limitations under the License.
 
 #include "tensorflow/c/c_api_experimental.h"
 #include "tensorflow/c/c_test_util.h"
+#include "tensorflow/core/lib/io/path.h"
+#include "tensorflow/core/platform/logging.h"
+#include "tensorflow/core/platform/test.h"
 
 namespace tensorflow {
 namespace {
 
-void TestIteratorStack() {
+void TestFakeIteratorStack() {
   TF_Status* s = TF_NewStatus();
   TF_Graph* graph = TF_NewGraph();
 
-  TF_Function* dataset_func = nullptr;
-
-  TF_Operation* get_next =
-      TF_MakeIteratorGetNextWithDatasets(graph, "dummy_path", &dataset_func, s);
+  TF_Operation* get_next = TF_MakeFakeIteratorGetNextWithDatasets(graph, s);
   ASSERT_EQ(TF_OK, TF_GetCode(s)) << TF_Message(s);
 
-  ASSERT_NE(dataset_func, nullptr);
-  TF_DeleteFunction(dataset_func);
-
   CSession csession(graph, s);
   ASSERT_EQ(TF_OK, TF_GetCode(s)) << TF_Message(s);
 
   // Run the graph.
-  for (int i = 0; i < 1; ++i) {
+  const float base_value = 42.0;
+  for (int i = 0; i < 3; ++i) {
     csession.SetOutputs({get_next});
     csession.Run(s);
     ASSERT_EQ(TF_OK, TF_GetCode(s)) << TF_Message(s);
     TF_Tensor* out = csession.output_tensor(0);
     ASSERT_TRUE(out != nullptr);
-    EXPECT_EQ(TF_INT32, TF_TensorType(out));
-    EXPECT_EQ(0, TF_NumDims(out));  // scalar
-    ASSERT_EQ(sizeof(int32), TF_TensorByteSize(out));
-    int32* output_contents = static_cast<int32*>(TF_TensorData(out));
-    EXPECT_EQ(1, *output_contents);
+    ASSERT_EQ(TF_FLOAT, TF_TensorType(out));
+    ASSERT_EQ(0, TF_NumDims(out));  // scalar
+    ASSERT_EQ(sizeof(float), TF_TensorByteSize(out));
+    float* output_contents = static_cast<float*>(TF_TensorData(out));
+    ASSERT_EQ(base_value + i, *output_contents);
   }
 
   // This should error out since we've exhausted the iterator.
@@ -60,7 +58,63 @@ void TestIteratorStack() {
   TF_DeleteStatus(s);
 }
 
-TEST(CAPI_EXPERIMENTAL, IteratorGetNext) { TestIteratorStack(); }
+TEST(CAPI_EXPERIMENTAL, FakeIteratorGetNext) { TestFakeIteratorStack(); }
+
+TEST(CAPI_EXPERIMENTAL, ImagenetIteratorGetNext) {
+  TF_Status* s = TF_NewStatus();
+  TF_Graph* graph = TF_NewGraph();
+
+  const string file_path = tensorflow::io::JoinPath(
+      tensorflow::testing::TensorFlowSrcRoot(), "c/testdata/tf_record");
+  VLOG(1) << "data file path is " << file_path;
+  const int batch_size = 64;
+  TF_Operation* get_next = TF_MakeImagenetIteratorGetNextWithDatasets(
+      graph, file_path.c_str(), batch_size, s);
+  ASSERT_EQ(TF_OK, TF_GetCode(s)) << TF_Message(s);
+
+  CSession csession(graph, s);
+  ASSERT_EQ(TF_OK, TF_GetCode(s)) << TF_Message(s);
+
+  // Run the graph.
+  // The two output tensors should look like:
+  // Tensor("IteratorGetNext:0", shape=(batch_size, 224, 224, 3), dtype=float32)
+  // Tensor("IteratorGetNext:1", shape=(batch_size, ), dtype=int32)
+  for (int i = 0; i < 3; ++i) {
+    LOG(INFO) << "Running iter " << i;
+    csession.SetOutputs({{get_next, 0}, {get_next, 1}});
+    csession.Run(s);
+    ASSERT_EQ(TF_OK, TF_GetCode(s)) << TF_Message(s);
+
+    {
+      TF_Tensor* image = csession.output_tensor(0);
+      ASSERT_TRUE(image != nullptr);
+      ASSERT_EQ(TF_FLOAT, TF_TensorType(image));
+      // Confirm shape is 224 X 224 X 3
+      ASSERT_EQ(4, TF_NumDims(image));
+      ASSERT_EQ(batch_size, TF_Dim(image, 0));
+      ASSERT_EQ(224, TF_Dim(image, 1));
+      ASSERT_EQ(224, TF_Dim(image, 2));
+      ASSERT_EQ(3, TF_Dim(image, 3));
+      ASSERT_EQ(sizeof(float) * batch_size * 224 * 224 * 3,
+                TF_TensorByteSize(image));
+    }
+
+    {
+      TF_Tensor* label = csession.output_tensor(1);
+      ASSERT_TRUE(label != nullptr);
+      ASSERT_EQ(TF_INT32, TF_TensorType(label));
+      ASSERT_EQ(1, TF_NumDims(label));
+      ASSERT_EQ(batch_size, TF_Dim(label, 0));
+      ASSERT_EQ(sizeof(int32) * batch_size, TF_TensorByteSize(label));
+    }
+  }
+
+  // Clean up
+  csession.CloseAndDelete(s);
+  ASSERT_EQ(TF_OK, TF_GetCode(s)) << TF_Message(s);
+  TF_DeleteGraph(graph);
+  TF_DeleteStatus(s);
+}
 
 }  // namespace
 }  // namespace tensorflow
diff --git a/tensorflow/c/testdata/tf_record b/tensorflow/c/testdata/tf_record
new file mode 100644 (file)
index 0000000..6e16076
Binary files /dev/null and b/tensorflow/c/testdata/tf_record differ