aboutsummaryrefslogtreecommitdiffhomepage
path: root/tensorflow/contrib/rate
diff options
context:
space:
mode:
authorGravatar Yifei Feng <yifeif@google.com>2018-08-21 14:48:01 -0700
committerGravatar TensorFlower Gardener <gardener@tensorflow.org>2018-08-21 15:00:13 -0700
commit0f02f05913e03889bbcb85e71a6d005a8519bfb9 (patch)
treec5b2bacb1b96d260b67cb56c208ce8f1b1025dae /tensorflow/contrib/rate
parent3f24f93c2a32b2eae8951e5b272c3b647c5b9611 (diff)
Merged commit includes the following changes:
209663919 by yifeif<yifeif@google.com>: Internal change. -- 209663914 by amitpatankar<amitpatankar@google.com>: Fix the topk_op_test for numpy>1.15. -- 209660476 by jdduke<jdduke@google.com>: Fix model lifetime for TensorFlow Lite C# bindings Ensure the model's existence for the duration of the interpreter, as per API requirements. -- 209655960 by scottzhu<scottzhu@google.com>: Unify RNN Cell interface between TF and Keras. -- 209655731 by A. Unique TensorFlower<gardener@tensorflow.org>: Added tests for PredictionOps and PartitionExamplesOps -- 209655291 by nolivia<nolivia@google.com>: adding rate class so that we can save global_step/sec using tf.contrib.summary. The function takes the rate in relation to any tensors provided that the numerator and denominator are broadcastable and have dtypes that can be cast to float64 -- 209654655 by kramerb<kramerb@google.com>: [XLA] Switch from tensorflow::gtl::InlinedVector to absl::InlinedVector This one comes with extra goodies like a move constructor. -- 209653851 by A. Unique TensorFlower<gardener@tensorflow.org>: Internal build specification change -- PiperOrigin-RevId: 209663919
Diffstat (limited to 'tensorflow/contrib/rate')
-rw-r--r--tensorflow/contrib/rate/BUILD48
-rw-r--r--tensorflow/contrib/rate/rate.py151
-rw-r--r--tensorflow/contrib/rate/rate_test.py97
3 files changed, 296 insertions, 0 deletions
diff --git a/tensorflow/contrib/rate/BUILD b/tensorflow/contrib/rate/BUILD
new file mode 100644
index 0000000000..c461a7145e
--- /dev/null
+++ b/tensorflow/contrib/rate/BUILD
@@ -0,0 +1,48 @@
+# Description:
+# contains parts of TensorFlow that are experimental or unstable and which are not supported.
+
+licenses(["notice"]) # Apache 2.0
+
+package(default_visibility = ["//visibility:public"])
+
+exports_files(["LICENSE"])
+
+load("//tensorflow:tensorflow.bzl", "py_test")
+
+py_library(
+ name = "rate",
+ srcs = [
+ "rate.py",
+ ],
+ srcs_version = "PY2AND3",
+ deps = [
+ "//tensorflow/python:array_ops",
+ "//tensorflow/python:check_ops",
+ "//tensorflow/python:control_flow_ops",
+ "//tensorflow/python:framework",
+ "//tensorflow/python:framework_for_generated_wrappers",
+ "//tensorflow/python:math_ops",
+ "//tensorflow/python:sparse_ops",
+ "//tensorflow/python:state_ops",
+ "//tensorflow/python:util",
+ "//tensorflow/python:variable_scope",
+ "//tensorflow/python:variables",
+ ],
+)
+
+py_test(
+ name = "rate_test",
+ size = "small",
+ srcs = ["rate_test.py"],
+ deps = [
+ ":rate",
+ "//tensorflow/python:array_ops",
+ "//tensorflow/python:client_testlib",
+ "//tensorflow/python:data_flow_ops",
+ "//tensorflow/python:errors",
+ "//tensorflow/python:framework",
+ "//tensorflow/python:framework_for_generated_wrappers",
+ "//tensorflow/python:variables",
+ "//tensorflow/python/eager:test",
+ ],
+)
diff --git a/tensorflow/contrib/rate/rate.py b/tensorflow/contrib/rate/rate.py
new file mode 100644
index 0000000000..24d586479a
--- /dev/null
+++ b/tensorflow/contrib/rate/rate.py
@@ -0,0 +1,151 @@
+# Copyright 2018 The TensorFlow Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ==============================================================================
+"""Implementation of tf.contrib.rate module."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import re
+
+from tensorflow.python.eager import context
+from tensorflow.python.eager import function
+from tensorflow.python.framework import dtypes
+from tensorflow.python.framework import ops
+from tensorflow.python.ops import array_ops
+from tensorflow.python.ops import math_ops
+from tensorflow.python.ops import resource_variable_ops
+from tensorflow.python.ops import state_ops
+from tensorflow.python.ops import variable_scope
+
+_to_replace = re.compile("[^A-Za-z0-9.]")
+
+
+class Rate(object):
+ """Computes the rate of change since the last rate call."""
+
+ def __init__(self, name=None):
+ self._built = False
+ self._vars = []
+ self._initial_values = {}
+ name = name or self.__class__.__name__
+ # Replace things like spaces in name to create a valid scope name.
+ scope_name = _to_replace.sub("_", name)
+ # We create the variable scope now to get the unique name that will
+ # be used as a variable prefix when build() calls _add_variable().
+ with variable_scope.variable_scope(
+ scope_name, use_resource=True, reuse=False) as scope:
+ pos = scope.name.rfind(scope_name)
+ self._name = name + scope.name[pos + len(scope_name):]
+ self._scope = scope
+
+ # Ensures that if the user calls build directly we still set self._built to
+ # True to prevent variables from being recreated.
+ self._build = self.build
+ if context.executing_eagerly():
+ self._construction_scope = context.eager_mode
+ else:
+ # We make self.call() into a graph callable here, so that we can
+ # return a single op that performs all of the variable updates.
+ self._construction_scope = ops.get_default_graph().as_default
+ self.call = function.defun(self.call)
+
+ def build(self, values, denominator):
+ """Method to create variables.
+
+ Called by `__call__()` before `call()` for the first time.
+
+ Args:
+ values: The numerator for rate.
+ denominator: Value to which the rate is taken with respect.
+ """
+ self.numer = self._add_variable(
+ name="numer", shape=values.get_shape(), dtype=dtypes.float64)
+ self.denom = self._add_variable(
+ name="denom", shape=denominator.get_shape(), dtype=dtypes.float64)
+ self.prev_values = self._add_variable(
+ name="prev_values", shape=values.get_shape(), dtype=dtypes.float64)
+ self.prev_denominator = self._add_variable(
+ name="prev_denominator",
+ shape=denominator.get_shape(),
+ dtype=dtypes.float64)
+ self._built = True
+
+ def __call__(self, *args, **kwargs):
+ """Returns op to execute to update.
+
+ Returns None if eager execution is enabled.
+ Returns a graph-mode function if graph execution is enabled.
+
+ Args:
+ *args:
+ **kwargs: A mini-batch of inputs to Rate, passed on to `call()`.
+ """
+ if not self._built:
+ with variable_scope.variable_scope(
+ self._scope), self._construction_scope():
+ self.build(*args, **kwargs)
+ self._built = True
+ return self.call(*args, **kwargs)
+
+ @property
+ def name(self):
+ return self._name
+
+ @property
+ def variables(self):
+ return self._vars
+
+ def _safe_div(self, numerator, denominator, name):
+ t = math_ops.truediv(numerator, denominator)
+ zero = array_ops.zeros_like(t, dtype=denominator.dtype)
+ condition = math_ops.greater(denominator, zero)
+ zero = math_ops.cast(zero, t.dtype)
+ return array_ops.where(condition, t, zero, name=name)
+
+ def _add_variable(self, name, shape=None, dtype=None):
+ """Private method for adding variables to the graph."""
+ if self._built:
+ raise RuntimeError("Can't call add_variable() except in build().")
+ v = resource_variable_ops.ResourceVariable(
+ lambda: array_ops.zeros(shape, dtype),
+ trainable=False,
+ validate_shape=True,
+ name=name,
+ collections=[ops.GraphKeys.LOCAL_VARIABLES])
+ return v
+
+ def call(self, values, denominator):
+ """Computes the rate since the last call.
+
+ Args:
+ values: Tensor with the per-example value.
+ denominator: Measure to take the rate with respect to.
+
+ Returns:
+ The rate or 0 if denominator is unchanged since last call.
+ """
+ if denominator.dtype != dtypes.float64:
+ denominator = math_ops.cast(denominator, dtypes.float64)
+ if values.dtype != dtypes.float64:
+ values = math_ops.cast(values, dtypes.float64)
+
+ state_ops.assign(self.numer, math_ops.subtract(values, self.prev_values))
+ state_ops.assign(self.denom,
+ math_ops.subtract(denominator, self.prev_denominator))
+ state_ops.assign(self.prev_values, values)
+ state_ops.assign(self.prev_denominator, denominator)
+
+ return self._safe_div(self.numer, self.denom, name="safe_rate")
diff --git a/tensorflow/contrib/rate/rate_test.py b/tensorflow/contrib/rate/rate_test.py
new file mode 100644
index 0000000000..08908104f4
--- /dev/null
+++ b/tensorflow/contrib/rate/rate_test.py
@@ -0,0 +1,97 @@
+# Copyright 2018 The TensorFlow Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ==============================================================================
+"""Tests for Rate."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+from tensorflow.contrib.rate import rate
+from tensorflow.python.framework import constant_op
+from tensorflow.python.framework import dtypes
+from tensorflow.python.framework import ops
+from tensorflow.python.framework import test_util
+from tensorflow.python.ops import array_ops
+from tensorflow.python.ops import control_flow_ops
+from tensorflow.python.ops import math_ops
+from tensorflow.python.ops import variables
+from tensorflow.python.platform import test
+
+
+class RateTest(test.TestCase):
+
+ @test_util.run_in_graph_and_eager_modes()
+ def testBuildRate(self):
+ m = rate.Rate()
+ m.build(
+ constant_op.constant([1], dtype=dtypes.float32),
+ constant_op.constant([2], dtype=dtypes.float32))
+ old_numer = m.numer
+ m(
+ constant_op.constant([2], dtype=dtypes.float32),
+ constant_op.constant([2], dtype=dtypes.float32))
+ self.assertTrue(old_numer is m.numer)
+
+ @test_util.run_in_graph_and_eager_modes()
+ def testBasic(self):
+ with self.test_session():
+ r_ = rate.Rate()
+ a = r_(array_ops.ones([1]), denominator=array_ops.ones([1]))
+ self.evaluate(variables.global_variables_initializer())
+ self.evaluate(variables.local_variables_initializer())
+ self.assertEqual([[1]], self.evaluate(a))
+ b = r_(constant_op.constant([2]), denominator=constant_op.constant([2]))
+ self.assertEqual([[1]], self.evaluate(b))
+ c = r_(constant_op.constant([4]), denominator=constant_op.constant([3]))
+ self.assertEqual([[2]], self.evaluate(c))
+ d = r_(constant_op.constant([16]), denominator=constant_op.constant([3]))
+ self.assertEqual([[0]], self.evaluate(d)) # divide by 0
+
+ def testNamesWithSpaces(self):
+ m1 = rate.Rate(name="has space")
+ m1(array_ops.ones([1]), array_ops.ones([1]))
+ self.assertEqual(m1.name, "has space")
+ self.assertEqual(m1.prev_values.name, "has_space_1/prev_values:0")
+
+ @test_util.run_in_graph_and_eager_modes()
+ def testWhileLoop(self):
+ with self.test_session():
+ r_ = rate.Rate()
+
+ def body(value, denom, i, ret_rate):
+ i += 1
+ ret_rate = r_(value, denom)
+ with ops.control_dependencies([ret_rate]):
+ value = math_ops.add(value, 2)
+ denom = math_ops.add(denom, 1)
+ return [value, denom, i, ret_rate]
+
+ def condition(v, d, i, r):
+ del v, d, r # unused vars by condition
+ return math_ops.less(i, 100)
+
+ i = constant_op.constant(0)
+ value = constant_op.constant([1], dtype=dtypes.float64)
+ denom = constant_op.constant([1], dtype=dtypes.float64)
+ ret_rate = r_(value, denom)
+ self.evaluate(variables.global_variables_initializer())
+ self.evaluate(variables.local_variables_initializer())
+ loop = control_flow_ops.while_loop(condition, body,
+ [value, denom, i, ret_rate])
+ self.assertEqual([[2]], self.evaluate(loop[3]))
+
+
+if __name__ == "__main__":
+ test.main()