aboutsummaryrefslogtreecommitdiffhomepage
path: root/tensorflow/contrib/lite/python/lite_test.py
diff options
context:
space:
mode:
authorGravatar Andrew Selle <aselle@google.com>2018-01-30 09:55:38 -0800
committerGravatar TensorFlower Gardener <gardener@tensorflow.org>2018-01-30 10:07:34 -0800
commit39bc42ebcf0df005b378fa88a4650a5bebb1eb0c (patch)
tree4308f7d16ab9011b707534322d4e0b25662354f0 /tensorflow/contrib/lite/python/lite_test.py
parent5ab07fcfc51fd524622e2c583f81f0cd8eca97d5 (diff)
Create an interface to create hints for future toco conversions.
Specifically, tf.contrib.lite.OpHint can create "breadcrumb" hints that describe encapsulation of multiple TensorFlow ops that make up a TensorFlow lite builtin or custom op. These can later be replaced with stub versions in a GraphDef or SavedModel. PiperOrigin-RevId: 183846742
Diffstat (limited to 'tensorflow/contrib/lite/python/lite_test.py')
-rw-r--r--tensorflow/contrib/lite/python/lite_test.py118
1 files changed, 117 insertions, 1 deletions
diff --git a/tensorflow/contrib/lite/python/lite_test.py b/tensorflow/contrib/lite/python/lite_test.py
index 7d55f3fe6f..b8b4510188 100644
--- a/tensorflow/contrib/lite/python/lite_test.py
+++ b/tensorflow/contrib/lite/python/lite_test.py
@@ -18,10 +18,14 @@ from __future__ import division
from __future__ import print_function
from tensorflow.contrib.lite.python import lite
+from tensorflow.contrib.lite.python.op_hint import _tensor_name_base as _tensor_name_base
from tensorflow.python.client import session
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import test_util
+from tensorflow.python.framework.graph_util_impl import _bfs_for_reachable_nodes
+from tensorflow.python.framework.graph_util_impl import _extract_graph_summary
from tensorflow.python.ops import array_ops
+from tensorflow.python.ops import math_ops
from tensorflow.python.platform import test
@@ -35,7 +39,8 @@ class LiteTest(test_util.TensorFlowTestCase):
# Try running on valid graph
result = lite.toco_convert(sess.graph_def, [in_tensor], [out_tensor])
self.assertTrue(result)
- # TODO(aselle): remove tests that fail.
+ # TODO(aselle): remove tests that fail (we must get TOCO to not fatal
+ # all the time).
# Try running on identity graph (known fail)
# with self.assertRaisesRegexp(RuntimeError, "!model->operators.empty()"):
# result = lite.toco_convert(sess.graph_def, [in_tensor], [in_tensor])
@@ -51,5 +56,116 @@ class LiteTest(test_util.TensorFlowTestCase):
quantized_input_stats=[(0., 1.)])
self.assertTrue(result)
+
+class LiteTestOpHint(test_util.TensorFlowTestCase):
+ """Test the hint to stub functionality."""
+
+ def _getGraphOpTypes(self, graphdef, output_nodes):
+ """Returns used op types in `graphdef` reachable from `output_nodes`.
+
+ This is used to check that after the stub transformation the expected
+ nodes are there. Typically use this with self.assertCountEqual(...).
+
+ NOTE: this is not a exact test that the graph is the correct output, but
+ it balances compact expressibility of test with sanity checking.
+
+ Args:
+ graphdef: TensorFlow proto graphdef.
+ output_nodes: A list of output node names that we need to reach.
+
+ Returns:
+ A set of node types reachable from `output_nodes`.
+ """
+ name_to_input_name, name_to_node, _ = (
+ _extract_graph_summary(graphdef))
+ # Find all nodes that are needed by the outputs
+ used_node_names = _bfs_for_reachable_nodes(output_nodes, name_to_input_name)
+ return set([name_to_node[node_name].op for node_name in used_node_names])
+
+ def _countIdentities(self, nodes):
+ """Count the number of "Identity" op types in the list of proto nodes.
+
+ Args:
+ nodes: NodeDefs of the graph.
+
+ Returns:
+ The number of nodes with op type "Identity" found.
+ """
+ return len([x for x in nodes if x.op == "Identity"])
+
+ def testSwishLiteHint(self):
+ """Makes a custom op swish and makes sure it gets converted as a unit."""
+ image = array_ops.constant([1., 2., 3., 4.])
+ swish_scale = array_ops.constant(1.0)
+
+ def _swish(input_tensor, scale):
+ custom = lite.OpHint("cool_activation")
+ input_tensor, scale = custom.add_inputs(input_tensor, scale)
+ output = math_ops.sigmoid(input_tensor) * input_tensor * scale
+ output, = custom.add_outputs(output)
+ return output
+ output = array_ops.identity(_swish(image, swish_scale), name="ModelOutput")
+
+ with self.test_session() as sess:
+ # check if identities have been put into the graph (2 input, 1 output,
+ # and 1 final output).
+ self.assertEqual(self._countIdentities(sess.graph_def.node), 4)
+
+ stubbed_graphdef = lite.convert_op_hints_to_stubs(sess)
+
+ self.assertCountEqual(
+ self._getGraphOpTypes(
+ stubbed_graphdef, output_nodes=[_tensor_name_base(output)]),
+ ["cool_activation", "Const", "Identity"])
+
+ def testScaleAndBiasAndIdentity(self):
+ """This tests a scaled add which has 3 inputs and 2 outputs."""
+ a = array_ops.constant(1.)
+ x = array_ops.constant([2., 3.])
+ b = array_ops.constant([4., 5.])
+
+ def _scaled_and_bias_and_identity(a, x, b):
+ custom = lite.OpHint("scale_and_bias_and_identity")
+ a, x, b = custom.add_inputs(a, x, b)
+ return custom.add_outputs(a * x + b, x)
+ output = array_ops.identity(_scaled_and_bias_and_identity(a, x, b),
+ name="ModelOutput")
+
+ with self.test_session() as sess:
+ # make sure one identity for each input (3) and output (2) => 3 + 2 = 5
+ # +1 for the final output
+ self.assertEqual(self._countIdentities(sess.graph_def.node), 6)
+
+ stubbed_graphdef = lite.convert_op_hints_to_stubs(sess)
+
+ self.assertCountEqual(
+ self._getGraphOpTypes(
+ stubbed_graphdef, output_nodes=[_tensor_name_base(output)]),
+ ["scale_and_bias_and_identity", "Const", "Identity", "Pack"])
+
+ def testTwoFunctions(self):
+ """Tests if two functions are converted correctly."""
+ a = array_ops.constant([1.])
+ b = array_ops.constant([1.])
+ def _double_values(x):
+ custom = lite.OpHint("add_test")
+ x = custom.add_inputs(x)
+ output = math_ops.multiply(x, x)
+ output, = custom.add_outputs(output)
+ return output
+ output = array_ops.identity(
+ math_ops.add(_double_values(a), _double_values(b)), name="ModelOutput")
+
+ with self.test_session() as sess:
+ # make sure one identity for each input (2) and output (2) => 2 + 2
+ # +1 for the final output
+ self.assertEqual(self._countIdentities(sess.graph_def.node), 5)
+ stubbed_graphdef = lite.convert_op_hints_to_stubs(sess)
+ self.assertCountEqual(
+ self._getGraphOpTypes(
+ stubbed_graphdef, output_nodes=[_tensor_name_base(output)]),
+ ["add_test", "Const", "Identity", "Add"])
+
+
if __name__ == "__main__":
test.main()