def testAssertDivideByZero(self): with self.test_session() as sess: epsilon = ops.convert_to_tensor(1e-20) x = ops.convert_to_tensor(0.0) y = ops.convert_to_tensor(1.0) z = ops.convert_to_tensor(2.0) # assert(epsilon < y) # z / y with sess.graph.control_dependencies([ control_flow_ops.Assert( math_ops.less(epsilon, y), ["Divide-by-zero"]) ]): out = math_ops.div(z, y) self.assertAllEqual(2.0, out.eval()) # assert(epsilon < x) # z / x # # This tests printing out multiple tensors with sess.graph.control_dependencies([ control_flow_ops.Assert( math_ops.less(epsilon, x), ["Divide-by-zero", "less than x"]) ]): out = math_ops.div(z, x) with self.assertRaisesOpError("less than x"): out.eval()
def _nest_where(vals, cases): assert len(vals) == len(cases) - 1 if len(vals) == 1: return array_ops.where( math_ops.less(l1_norm, const(vals[0])), cases[0], cases[1]) else: return array_ops.where( math_ops.less(l1_norm, const(vals[0])), cases[0], _nest_where(vals[1:], cases[1:]))
def testCorrectlyPicksVector(self): with self.cached_session(): x = np.arange(10, 12) y = np.arange(15, 18) self.assertAllEqual( x, self.evaluate(du.pick_vector(math_ops.less(0, 5), x, y))) self.assertAllEqual( y, self.evaluate(du.pick_vector(math_ops.less(5, 0), x, y))) self.assertAllEqual(x, du.pick_vector( constant_op.constant(True), x, y)) # No eval. self.assertAllEqual(y, du.pick_vector( constant_op.constant(False), x, y)) # No eval.
def random_flip_left_right(image, seed=None): """Randomly flip an image horizontally (left to right). With a 1 in 2 chance, outputs the contents of `image` flipped along the second dimension, which is `width`. Otherwise output the image as-is. Args: image: A 3-D tensor of shape `[height, width, channels].` seed: A Python integer. Used to create a random seed. See @{tf.set_random_seed} for behavior. Returns: A 3-D tensor of the same type and shape as `image`. Raises: ValueError: if the shape of `image` not supported. """ image = ops.convert_to_tensor(image, name='image') _Check3DImage(image, require_static=False) uniform_random = random_ops.random_uniform([], 0, 1.0, seed=seed) mirror_cond = math_ops.less(uniform_random, .5) result = control_flow_ops.cond(mirror_cond, lambda: array_ops.reverse(image, [1]), lambda: image) return fix_image_flip_shape(image, result)
def setUpClass(cls): cls._dump_root = tempfile.mkdtemp() with session.Session() as sess: loop_var = constant_op.constant(0, name="while_loop_test/loop_var") cond = lambda loop_var: math_ops.less(loop_var, 10) body = lambda loop_var: math_ops.add(loop_var, 1) while_loop = control_flow_ops.while_loop(cond, body, [loop_var], parallel_iterations=1) run_options = config_pb2.RunOptions(output_partition_graphs=True) debug_url = "file://%s" % cls._dump_root watch_opts = run_options.debug_tensor_watch_opts # Add debug tensor watch for "while/Identity". watch = watch_opts.add() watch.node_name = "while/Identity" watch.output_slot = 0 watch.debug_ops.append("DebugIdentity") watch.debug_urls.append(debug_url) # Invoke Session.run(). run_metadata = config_pb2.RunMetadata() sess.run(while_loop, options=run_options, run_metadata=run_metadata) cls._debug_dump = debug_data.DebugDumpDir(cls._dump_root, partition_graphs=run_metadata.partition_graphs) cls._analyzer = analyzer_cli.DebugAnalyzer(cls._debug_dump) cls._registry = debugger_cli_common.CommandHandlerRegistry() cls._registry.register_command_handler( "list_tensors", cls._analyzer.list_tensors, cls._analyzer.get_help("list_tensors"), prefix_aliases=["lt"] ) cls._registry.register_command_handler( "print_tensor", cls._analyzer.print_tensor, cls._analyzer.get_help("print_tensor"), prefix_aliases=["pt"] )
def testSelectOp(self): if test.is_gpu_available(cuda_only=True): random_seed.set_random_seed(0) x = random_ops.truncated_normal([1, 784], seed=0) conv = _two_layer_model(x) add = math_ops.add(conv, conv) mean = math_ops.reduce_mean(conv) condition = math_ops.less(conv, mean) select = gen_math_ops._select(condition, conv, add) output = array_ops.identity(select) with session.Session() as sess: output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() output_val = sess.run(output, run_metadata=metadata) nodes = [] num_transposes = 0 for node in metadata.cost_graph.node: if _is_transpose(node.name): num_transposes += 1 nodes.append(node.name) expected_num_transposes = 2 self.assertEqual(expected_num_transposes, num_transposes) self._assert_trans_nhwc_to_nchw('Conv2D-0', nodes) self._assert_trans_nchw_to_nhwc('Select-0-0', nodes) self.assertAllClose(output_val_ref, output_val, atol=1e-3)
def testCorrectlyPicksVector(self): with self.test_session(): x = np.arange(10, 12) y = np.arange(15, 18) self.assertAllEqual(x, distribution_util.pick_vector( math_ops.less(0, 5), x, y).eval()) self.assertAllEqual(y, distribution_util.pick_vector( math_ops.less(5, 0), x, y).eval()) self.assertAllEqual(x, distribution_util.pick_vector( constant_op.constant(True), x, y)) # No eval. self.assertAllEqual(y, distribution_util.pick_vector( constant_op.constant(False), x, y)) # No eval.
def createAndRunGraphWithWhileLoop(self): """Create and run a TensorFlow Graph with a while loop to generate dumps.""" self.dump_root = self.get_temp_dir() self.curr_file_path = os.path.abspath( tf_inspect.getfile(tf_inspect.currentframe())) # Run a simple TF graph to generate some debug dumps that can be used in # source annotation. with session.Session() as sess: loop_body = lambda i: math_ops.add(i, 2) self.traceback_first_line = line_number_above() loop_cond = lambda i: math_ops.less(i, 16) i = constant_op.constant(10, name="i") loop = control_flow_ops.while_loop(loop_cond, loop_body, [i]) run_options = config_pb2.RunOptions(output_partition_graphs=True) debug_utils.watch_graph( run_options, sess.graph, debug_urls=["file://%s" % self.dump_root]) run_metadata = config_pb2.RunMetadata() sess.run(loop, options=run_options, run_metadata=run_metadata) self.dump = debug_data.DebugDumpDir( self.dump_root, partition_graphs=run_metadata.partition_graphs) self.dump.set_python_graph(sess.graph)
def random_flip_left_right(image, seed=None): """Randomly flip an image horizontally (left to right). With a 1 in 2 chance, outputs the contents of `image` flipped along the second dimension, which is `width`. Otherwise output the image as-is. Args: image: A 3-D tensor of shape `[height, width, channels].` seed: A Python integer. Used to create a random seed. See [`set_random_seed`](../../api_docs/python/constant_op.md#set_random_seed) for behavior. Returns: A 3-D tensor of the same type and shape as `image`. Raises: ValueError: if the shape of `image` not supported. """ image = ops.convert_to_tensor(image, name='image') _Check3DImage(image, require_static=False) uniform_random = random_ops.random_uniform([], 0, 1.0, seed=seed) mirror_cond = math_ops.less(uniform_random, .5) stride = array_ops.where(mirror_cond, -1, 1) result = image[:, ::stride, :] return fix_image_flip_shape(image, result)
def _Solve(a, b, c): """Return solution of a quadratic minimization. The optimization equation is: f(a, b, c) = argmin_w{1/2 * a * w^2 + b * w + c * |w|} we get optimal solution w*: w* = -(b - sign(b)*c)/a if |b| > c else w* = 0 REQUIRES: Dimensionality of a and b must be same Args: a: A Tensor b: A Tensor c: A Tensor with one element. Returns: A Tensor w, which is solution for the equation """ with ops.name_scope("solve_" + b.op.name): c = ops.convert_to_tensor(c) k = array_ops.fill(array_ops.shape(b), c) zero_t = array_ops.zeros(array_ops.shape(b), dtype=b.dtype) w = (c * math_ops.sign(b) - b) / a w = math_ops.select(math_ops.less(math_ops.abs(b), k), zero_t, w) return w
def random_flip_up_down(image, seed=None): """Randomly flips an image vertically (upside down). With a 1 in 2 chance, outputs the contents of `image` flipped along the first dimension, which is `height`. Otherwise output the image as-is. Args: image: A 3-D tensor of shape `[height, width, channels].` seed: A Python integer. Used to create a random seed. See [`set_random_seed`](../../api_docs/python/constant_op.md#set_random_seed) for behavior. Returns: A 3-D tensor of the same type and shape as `image`. Raises: ValueError: if the shape of `image` not supported. """ image = ops.convert_to_tensor(image, name='image') _Check3DImage(image, require_static=False) uniform_random = random_ops.random_uniform([], 0, 1.0, seed=seed) mirror_cond = math_ops.less(uniform_random, .5) result = control_flow_ops.cond(mirror_cond, lambda: array_ops.reverse(image, [0]), lambda: image) return fix_image_flip_shape(image, result)
def testWhileWithScopedAllocator(self): group_size = 2 group_key = 1 instance_key0 = 1 instance_key1 = 2 config = config_pb2.ConfigProto(device_count={'CPU': group_size}) rewrite_options = config.graph_options.rewrite_options rewrite_options.scoped_allocator_optimization = ( rewriter_config_pb2.RewriterConfig.ON) del rewrite_options.scoped_allocator_opts.enable_op[:] rewrite_options.scoped_allocator_opts.enable_op.append('CollectiveReduce') with self.session(config=config) as sess: run_ops = [] for i in range(group_size): with ops.device('CPU:%d' % i): constant = constant_op.constant(0.) cond = lambda i: math_ops.less(i, 10.) body = lambda i: math_ops.add(i, 1.) input0 = control_flow_ops.while_loop(cond, body, [constant]) input1 = math_ops.add(constant, 5) colred0 = collective_ops.all_reduce(input0, group_size, group_key, instance_key0, 'Add', 'Id') colred1 = collective_ops.all_reduce(input1, group_size, group_key, instance_key1, 'Add', 'Id') run_ops.append(math_ops.add_n([colred0, colred1])) results = sess.run(run_ops) self.assertEqual(results, [30., 30.])
def _symmetric_matrix_square_root(mat, eps=1e-10): """Compute square root of a symmetric matrix. Note that this is different from an elementwise square root. We want to compute M' where M' = sqrt(mat) such that M' * M' = mat. Also note that this method **only** works for symmetric matrices. Args: mat: Matrix to take the square root of. eps: Small epsilon such that any element less than eps will not be square rooted to guard against numerical instability. Returns: Matrix square root of mat. """ # Unlike numpy, tensorflow's return order is (s, u, v) s, u, v = linalg_ops.svd(mat) # sqrt is unstable around 0, just use 0 in such case si = array_ops.where(math_ops.less(s, eps), s, math_ops.sqrt(s)) # Note that the v returned by Tensorflow is v = V # (when referencing the equation A = U S V^T) # This is unlike Numpy which returns v = V^T return math_ops.matmul( math_ops.matmul(u, array_ops.diag(si)), v, transpose_b=True)
def testControlFlow(self): with self.cached_session() as sess: v0 = variables.Variable(0, name="v0") var_dict = {} # Call get_variable in each of the cond clauses. def var_in_then_clause(): v1 = variables.Variable(1, name="v1") var_dict["v1"] = v1 return v1 + v0 def var_in_else_clause(): v2 = variables.Variable(2, name="v2") var_dict["v2"] = v2 return v2 + v0 add = control_flow_ops.cond( math_ops.less(v0, 10), var_in_then_clause, var_in_else_clause) v1 = var_dict["v1"] v2 = var_dict["v2"] # We should be able to initialize and run v1 and v2 without initializing # v0, even if the variable was created with a control dep on v0. self.evaluate(v1.initializer) self.assertEqual([1], self.evaluate(v1)) self.evaluate(v2.initializer) self.assertEqual([2], self.evaluate(v2)) # v0 should still be uninitialized. with self.assertRaisesRegexp(errors_impl.OpError, "uninitialized"): self.evaluate(v0) # We should not be able to run 'add' yet. with self.assertRaisesRegexp(errors_impl.OpError, "uninitialized"): self.evaluate(add) # If we initialize v0 we should be able to run 'add'. self.evaluate(v0.initializer) self.evaluate(add)
def random_flip_left_right(image, bboxes, seed=None): """Random flip left-right of an image and its bounding boxes. """ def flip_bboxes(bboxes): """Flip bounding boxes coordinates. """ bboxes = tf.stack([bboxes[:, 0], 1 - bboxes[:, 3], bboxes[:, 2], 1 - bboxes[:, 1]], axis=-1) return bboxes # Random flip. Tensorflow implementation. with tf.name_scope('random_flip_left_right'): image = ops.convert_to_tensor(image, name='image') _Check3DImage(image, require_static=False) uniform_random = random_ops.random_uniform([], 0, 1.0, seed=seed) mirror_cond = math_ops.less(uniform_random, .5) # Flip image. result = control_flow_ops.cond(mirror_cond, lambda: array_ops.reverse_v2(image, [1]), lambda: image) # Flip bboxes. bboxes = control_flow_ops.cond(mirror_cond, lambda: flip_bboxes(bboxes), lambda: bboxes) return fix_image_flip_shape(image, result), bboxes
def testWhileLoopWithSingleVariable(self): i = constant_op.constant(0) c = lambda i: math_ops.less(i, 10) b = lambda i: math_ops.add(i, 1) r = control_flow_ops.while_loop(c, b, [i]) self.assertEqual(self.evaluate(r), 10)
def _get_stratified_batch_from_tensors(val_list, label, accept_probs, batch_size, queue_threads=3): """Accepts examples one-at-a-time based on class.""" # Make queue that will have proper class proportions. Contains exactly one # batch at a time. vals_shapes = [val.get_shape() for val in val_list] vals_dtypes = [val.dtype for val in val_list] label_shape = label.get_shape() final_q = data_flow_ops.FIFOQueue(capacity=batch_size, shapes=vals_shapes + [label_shape], dtypes=vals_dtypes + [label.dtype], name='batched_queue') # Conditionally enqueue. tensors_to_enqueue = val_list + [label] eq_tf = array_ops.reshape(math_ops.less( random_ops.random_uniform([1]), array_ops.slice(accept_probs, [label], [1])), []) conditional_enqueue = control_flow_ops.cond( eq_tf, lambda: final_q.enqueue(tensors_to_enqueue), control_flow_ops.no_op) queue_runner.add_queue_runner(queue_runner.QueueRunner( final_q, [conditional_enqueue] * queue_threads)) return final_q.dequeue_many(batch_size)
def _flip_vector_to_matrix_dynamic(vec, batch_shape): """flip_vector_to_matrix with dynamic shapes.""" # Shapes associated with batch_shape batch_rank = array_ops.size(batch_shape) # Shapes associated with vec. vec = ops.convert_to_tensor(vec, name="vec") vec_shape = array_ops.shape(vec) vec_rank = array_ops.rank(vec) vec_batch_rank = vec_rank - 1 m = vec_batch_rank - batch_rank # vec_shape_left = [M1,...,Mm] or []. vec_shape_left = array_ops.slice(vec_shape, [0], [m]) # If vec_shape_left = [], then condensed_shape = [1] since reduce_prod([]) = 1 # If vec_shape_left = [M1,...,Mm], condensed_shape = [M1*...*Mm] condensed_shape = [math_ops.reduce_prod(vec_shape_left)] k = array_ops.gather(vec_shape, vec_rank - 1) new_shape = array_ops.concat(0, (batch_shape, [k], condensed_shape)) def _flip_front_dims_to_back(): # Permutation corresponding to [N1,...,Nn] + [k, M1,...,Mm] perm = array_ops.concat( 0, (math_ops.range(m, vec_rank), math_ops.range(0, m))) return array_ops.transpose(vec, perm=perm) x_flipped = control_flow_ops.cond( math_ops.less(0, m), _flip_front_dims_to_back, lambda: array_ops.expand_dims(vec, -1)) return array_ops.reshape(x_flipped, new_shape)
def assert_less(x, y, data=None, summarize=None, name=None): """Assert the condition `x < y` holds element-wise. This condition holds if for every pair of (possibly broadcast) elements `x[i]`, `y[i]`, we have `x[i] < y[i]`. If both `x` and `y` are empty, this is trivially satisfied. Args: x: Numeric `Tensor`. y: Numeric `Tensor`, same dtype as and broadcastable to `x`. data: The tensors to print out if the condition is False. Defaults to error message and first few entries of `x`, `y`. summarize: Print this many entries of each tensor. name: A name for this operation (optional). Defaults to "assert_less". Returns: Op that raises `InvalidArgumentError` if `x < y` is False. """ with ops.op_scope([x, y, data], name, 'assert_less'): x = ops.convert_to_tensor(x, name='x') y = ops.convert_to_tensor(y, name='y') if data is None: data = [ 'Condition x < y did not hold element-wise: x = ', x.name, x, 'y = ', y.name, y ] condition = math_ops.reduce_all(math_ops.less(x, y)) return logging_ops.Assert(condition, data, summarize=summarize)
def is_strictly_increasing(x, name=None): """Returns `True` if `x` is strictly increasing. Elements of `x` are compared in row-major order. The tensor `[x[0],...]` is strictly increasing if for every adjacent pair we have `x[i] < x[i+1]`. If `x` has less than two elements, it is trivially strictly increasing. See also: `is_non_decreasing` Args: x: Numeric `Tensor`. name: A name for this operation (optional). Defaults to "is_strictly_increasing" Returns: Boolean `Tensor`, equal to `True` iff `x` is strictly increasing. Raises: TypeError: if `x` is not a numeric tensor. """ with ops.op_scope([x], name, "is_strictly_increasing"): diff = _get_diff_for_monotonic_comparison(x) # When len(x) = 1, diff = [], less = [], and reduce_all([]) = True. zero = ops.convert_to_tensor(0, dtype=diff.dtype) return math_ops.reduce_all(math_ops.less(zero, diff))
def testCondFalse(self): x = constant_op.constant(2) y = constant_op.constant(1) z = control_flow_ops.cond( math_ops.less( x, y), lambda: math_ops.multiply(x, 17), lambda: math_ops.add(y, 23)) self.assertEquals(self.evaluate(z), 24)
def testCondTrueLegacy(self): x = constant_op.constant(2) y = constant_op.constant(5) z = control_flow_ops.cond( math_ops.less(x, y), fn1=lambda: math_ops.multiply(x, 17), fn2=lambda: math_ops.add(y, 23)) self.assertEquals(self.evaluate(z), 34)
def testEagerWhileLoopWithSingleVariable_bodyReturnsTuple(self): i = constant_op.constant(0) c = lambda i: math_ops.less(i, 10) b = lambda i: (math_ops.add(i, 1),) r = control_flow_ops.while_loop(c, b, [i]) # Expect a tuple since that is what the body returns. self.assertEqual(self.evaluate(r), (10,))
def testReconstructGraphWithWhileLoop(self): with session.Session(config=self._no_rewrite_session_config()) as sess: loop_body = lambda i: math_ops.add(i, 2) loop_cond = lambda i: math_ops.less(i, 16) i = constant_op.constant(10, name="i") loop = control_flow_ops.while_loop(loop_cond, loop_body, [i]) self._compareOriginalAndReconstructedGraphDefs(sess, loop)
def _cdf(self, x): # we use the same notation here as in wikipedia for the t = (x - self.mu) / self.sigma x_t = self.df / (math_ops.square(t) + self.df) # The cdf is defined differently for positive and negative t positive_cdf = 1. - 0.5 * math_ops.betainc(0.5 * self.df, 0.5, x_t) negative_cdf = 0.5 * math_ops.betainc(0.5 * self.df, 0.5, x_t) return array_ops.where(math_ops.less(t, 0), negative_cdf, positive_cdf)
def testCondFalseLegacy(self): with self.test_session(): x = constant_op.constant(2) y = constant_op.constant(1) z = control_flow_ops.cond( math_ops.less(x, y), fn1=lambda: math_ops.multiply(x, 17), fn2=lambda: math_ops.add(y, 23)) self.assertEquals(z.eval(), 24)
def testCondTrue(self): with self.test_session(): x = constant_op.constant(2) y = constant_op.constant(5) z = control_flow_ops.cond( math_ops.less(x, y), lambda: math_ops.multiply(x, 17), lambda: math_ops.add(y, 23)) self.assertEquals(z.eval(), 34)
def training_graph(self, input_data, input_labels, data_spec=None, **tree_kwargs): """Constructs a TF graph for training a random forest. Args: input_data: A tensor or SparseTensor or placeholder for input data. input_labels: A tensor or placeholder for labels associated with input_data. data_spec: A list of tf.dtype values specifying the original types of each column. **tree_kwargs: Keyword arguments passed to each tree's training_graph. Returns: The last op in the random forest training graph. """ data_spec = [constants.DATA_FLOAT] if data_spec is None else data_spec tree_graphs = [] for i in range(self.params.num_trees): with ops.device(self.device_assigner.get_device(i)): seed = self.params.base_random_seed if seed != 0: seed += i # If using bagging, randomly select some of the input. tree_data = input_data tree_labels = input_labels if self.params.bagging_fraction < 1.0: # TODO(thomaswc): This does sampling without replacment. Consider # also allowing sampling with replacement as an option. batch_size = array_ops.slice( array_ops.shape(input_data), [0], [1]) r = random_ops.random_uniform(batch_size, seed=seed) mask = math_ops.less( r, array_ops.ones_like(r) * self.params.bagging_fraction) gather_indices = array_ops.squeeze( array_ops.where(mask), squeeze_dims=[1]) # TODO(thomaswc): Calculate out-of-bag data and labels, and store # them for use in calculating statistics later. tree_data = array_ops.gather(input_data, gather_indices) tree_labels = array_ops.gather(input_labels, gather_indices) if self.params.bagged_features: tree_data = self._bag_features(i, tree_data) initialization = self.trees[i].tree_initialization() with ops.control_dependencies([initialization]): tree_graphs.append(self.trees[i].training_graph( tree_data, tree_labels, seed, data_spec=data_spec, **tree_kwargs)) return control_flow_ops.group(*tree_graphs, name='train')
def _mode(self): s = self.df - self.dimension - 1. s = array_ops.where( math_ops.less(s, 0.), constant_op.constant(float("NaN"), dtype=self.dtype, name="nan"), s) if self.cholesky_input_output_matrices: return math_ops.sqrt(s) * self.scale_operator_pd.sqrt_to_dense() return s * self.scale_operator_pd.to_dense()
def _SegmentMaxGrad(op, grad): """Gradient for SegmentMax.""" zeros = array_ops.zeros(array_ops.shape(op.inputs[0]), dtype=op.inputs[0].dtype) gathered_grads = array_ops.gather(grad, op.inputs[1]) gathered_outputs = array_ops.gather(op.outputs[0], op.inputs[1]) return math_ops.select(math_ops.less(op.inputs[0], gathered_outputs), zeros, gathered_grads), None
def _cdf(self, x): # Take Abs(scale) to make subsequent where work correctly. y = (x - self.loc) / math_ops.abs(self.scale) x_t = self.df / (y**2. + self.df) neg_cdf = 0.5 * math_ops.betainc(0.5 * self.df, 0.5, x_t) return array_ops.where(math_ops.less(y, 0.), neg_cdf, 1. - neg_cdf)
def stratified_sample(tensors, labels, target_probs, batch_size, init_probs=None, enqueue_many=False, queue_capacity=16, threads_per_queue=1, name=None): """Stochastically creates batches based on per-class probabilities. This method discards examples. Internally, it creates one queue to amortize the cost of disk reads, and one queue to hold the properly-proportioned batch. Args: tensors: List of tensors for data. All tensors are either one item or a batch, according to enqueue_many. labels: Tensor for label of data. Label is a single integer or a batch, depending on enqueue_many. It is not a one-hot vector. target_probs: Target class proportions in batch. An object whose type has a registered Tensor conversion function. batch_size: Size of batch to be returned. init_probs: Class proportions in the data. An object whose type has a registered Tensor conversion function, or `None` for estimating the initial distribution. enqueue_many: Bool. If true, interpret input tensors as having a batch dimension. queue_capacity: Capacity of the large queue that holds input examples. threads_per_queue: Number of threads for the large queue that holds input examples and for the final queue with the proper class proportions. name: Optional prefix for ops created by this function. Raises: ValueError: enqueue_many is True and labels doesn't have a batch dimension, or if enqueue_many is False and labels isn't a scalar. ValueError: enqueue_many is True, and batch dimension on data and labels don't match. ValueError: if probs don't sum to one. ValueError: if a zero initial probability class has a nonzero target probability. TFAssertion: if labels aren't integers in [0, num classes). Returns: (data_batch, label_batch), where data_batch is a list of tensors of the same length as `tensors` Example: # Get tensor for a single data and label example. data, label = data_provider.Get(['data', 'label']) # Get stratified batch according to per-class probabilities. target_probs = [...distribution you want...] [data_batch], labels = tf.contrib.training.stratified_sample( [data], label, target_probs) # Run batch through network. ... """ with ops.name_scope(name, 'stratified_sample', tensors + [labels]): tensor_list = ops.convert_n_to_tensor_or_indexed_slices(tensors) labels = ops.convert_to_tensor(labels) target_probs = ops.convert_to_tensor(target_probs, dtype=dtypes.float32) # Reduce the case of a single example to that of a batch of size 1. if not enqueue_many: tensor_list = [ array_ops.expand_dims(tensor, 0) for tensor in tensor_list ] labels = array_ops.expand_dims(labels, 0) # If `init_probs` is `None`, set up online estimation of data distribution. if init_probs is None: # We use `target_probs` to get the number of classes, so its shape must be # fully defined at graph construction time. target_probs.get_shape().assert_is_fully_defined() init_probs = _estimate_data_distribution( labels, target_probs.get_shape().num_elements()) else: init_probs = ops.convert_to_tensor(init_probs, dtype=dtypes.float32) # Validate that input is consistent. tensor_list, labels, [init_probs, target_probs ] = _verify_input(tensor_list, labels, [init_probs, target_probs]) # Check that all zero initial probabilities also have zero target # probabilities. assert_op = control_flow_ops.Assert( math_ops.reduce_all( math_ops.logical_or(math_ops.not_equal(init_probs, 0), math_ops.equal(target_probs, 0))), [ 'All classes with zero initial probability must also have zero target ' 'probability: ', init_probs, target_probs ]) init_probs = control_flow_ops.with_dependencies([assert_op], init_probs) # Calculate acceptance sampling probabilities. accept_probs = _calculate_acceptance_probabilities( init_probs, target_probs) proportion_rejected = math_ops.reduce_sum( (1 - accept_probs) * init_probs) accept_probs = control_flow_ops.cond( math_ops.less(proportion_rejected, .5), lambda: accept_probs, lambda: logging_ops.Print( # pylint: disable=g-long-lambda accept_probs, [accept_probs], message='Proportion of examples rejected by sampler is high.', first_n=10)) # Make a single queue to hold input examples. Reshape output so examples # don't have singleton batch dimension. batched = input_ops.batch(tensor_list + [labels], batch_size=1, num_threads=threads_per_queue, capacity=queue_capacity, enqueue_many=True) val_list = [array_ops.squeeze(x, [0]) for x in batched[:-1]] label = array_ops.squeeze(batched[-1], [0]) # Set up second queue containing batches that have the desired class # proportions. cur_prob = array_ops.gather(accept_probs, label) batched = input_ops.maybe_batch( val_list + [label], keep_input=random_ops.random_uniform([]) < cur_prob, batch_size=batch_size, num_threads=threads_per_queue) return batched[:-1], batched[-1]
def b(i, r): return i + 1, array_ops.where( math_ops.less(i, squarings), math_ops.matmul(r, r), r)
def c(x): return math_ops.less(x, 10)
def my_conditional(x): if math_ops.less(math_ops.reduce_sum(x), 0.0): return math_ops.log(x) else: return math_ops.log(-x)
def _run_condition(step_number, *unused): del unused # not part of while loop run condition return math_ops.less(step_number, window_size)
def sample(self): p = tf.sigmoid(self.logits) u = tf.random_uniform(tf.shape(p)) return tf.to_float(math_ops.less(u, p))
def bucket_by_sequence_length(input_length, tensors, batch_size, bucket_boundaries, num_threads=1, capacity=32, shapes=None, dynamic_pad=False, allow_smaller_final_batch=False, keep_input=None, shared_name=None, name=None): """Lazy bucketing of inputs according to their length. This method calls `tf.contrib.training.bucket` under the hood, after first subdividing the bucket boundaries into separate buckets and identifying which bucket the given `input_length` belongs to. See the documentation for `which_bucket` for details of the other arguments. Args: input_length: `int32` scalar `Tensor`, the sequence length of tensors. tensors: The list or dictionary of tensors, representing a single element, to bucket. Nested lists are not supported. batch_size: The new batch size pulled from the queue (all queues will have the same size). If a list is passed in then each bucket will have a different batch_size. (python int, int32 scalar or iterable of integers of length num_buckets). bucket_boundaries: int list, increasing non-negative numbers. The edges of the buckets to use when bucketing tensors. Two extra buckets are created, one for `input_length < bucket_boundaries[0]` and one for `input_length >= bucket_boundaries[-1]`. num_threads: An integer. The number of threads enqueuing `tensors`. capacity: An integer. The maximum number of minibatches in the top queue, and also the maximum number of elements within each bucket. shapes: (Optional) The shapes for each example. Defaults to the inferred shapes for `tensors`. dynamic_pad: Boolean. Allow variable dimensions in input shapes. The given dimensions are padded upon dequeue so that tensors within a batch have the same shapes. allow_smaller_final_batch: (Optional) Boolean. If `True`, allow the final batches to be smaller if there are insufficient items left in the queues. keep_input: (Optional). A `bool` scalar Tensor. If provided, this tensor controls whether the input is added to the queue or not. If it evaluates `True`, then `tensors` are added to the bucket; otherwise they are dropped. This tensor essentially acts as a filtering mechanism. The default behavior is to assume `keep_input=True`. shared_name: (Optional). If set, the queues will be shared under the given name across multiple sessions. name: (Optional) A name for the operations. Returns: A tuple `(sequence_length, outputs)` where `sequence_length` is a 1-D `Tensor` of size `batch_size` and `outputs` is a list or dictionary of batched, bucketed, outputs corresponding to elements of `tensors`. Raises: TypeError: if `bucket_boundaries` is not a list of python integers. ValueError: if `bucket_boundaries` is empty or contains non-increasing values or if batch_size is a list and it's length doesn't equal the number of buckets. """ tensor_list = _as_tensor_list(tensors) if not isinstance(bucket_boundaries, (list, tuple)): raise TypeError( "bucket_boundaries must be a list or tuple, but received: %s" % bucket_boundaries) if not bucket_boundaries: raise ValueError("bucket_boundaries must not be empty") for (s, e) in zip(bucket_boundaries[:-1], bucket_boundaries[1:]): if not isinstance(s, int) or not isinstance(e, int): raise TypeError( "bucket boundaries must be integers, but saw: %s and %s" % (s, e)) if s >= e: raise ValueError( "Buckets must contain sequential increasing lengths, but saw: " "%d before %d" % (s, e)) with ops.name_scope(name, "bucket_by_sequence_length", [input_length] + tensor_list) as name: input_length = ops.convert_to_tensor(input_length, dtype=dtypes.int32, name="input_length") # Bucketing conditions are: # l < b[0] # b[0] <= l < b[1] # b[1] <= l < b[2] # ... # b[N-2] <= l < b[N-1] # b[N-1] <= l # Equivalent to: # [-inf, b[0], b[1], ..., b[N-1]] <= l < [b[0], b[1], ..., b[N-1], inf] buckets_min = [np.iinfo(np.int32).min] + list(bucket_boundaries) buckets_max = list(bucket_boundaries) + [np.iinfo(np.int32).max] conditions_c = math_ops.logical_and( math_ops.less_equal(buckets_min, input_length), math_ops.less(input_length, buckets_max)) which_bucket = math_ops.reduce_min(array_ops.where(conditions_c)) which_bucket = math_ops.to_int32(which_bucket) if shapes is not None: shapes = [tensor_shape.scalar()] + shapes _, dequeued = bucket( tensors=[input_length] + tensor_list, which_bucket=which_bucket, batch_size=batch_size, num_buckets=len(bucket_boundaries) + 1, num_threads=num_threads, capacity=capacity, shapes=shapes, dynamic_pad=dynamic_pad, allow_smaller_final_batch=allow_smaller_final_batch, keep_input=keep_input, shared_name=shared_name) return (dequeued[0], _as_original_type(tensors, dequeued[1:]))
def sample(self): u = tf.random_uniform(tf.shape(self.ps)) return tf.to_float(math_ops.less(u, self.ps))
def _while_condition(iteration_number, *unused_args): return math_ops.less(iteration_number, prediction_iterations)
def condition(i, *args): return math_ops.less(i, self.num_groups)
def build_controller(self): """RL optimization interface. Returns: ops: A dictionary holding handles of the model used for training. """ self._global_step = training_util.get_or_create_global_step() ops = {} ops["loss"] = 0 failing_signal = self.compute_reward(self.hparams.failing_signal) ctr = {} with tf_ops.name_scope("controller_{}".format(self.ctrl_id)): with variable_scope.variable_scope("controller_{}".format( self.ctrl_id)): ctr["reward"] = {"value": [], "ph": [], "update": []} ctr["ready"] = {"value": [], "ph": [], "update": []} ctr["best_reward"] = {"value": [], "update": []} for i in range(self.hparams.num_children): reward_value = variable_scope.get_local_variable( "reward_{}".format(i), initializer=0.0, dtype=dtypes.float32, trainable=False) reward_ph = array_ops.placeholder( dtypes.float32, shape=(), name="reward_ph_{}".format(i)) reward_update = state_ops.assign(reward_value, reward_ph, use_locking=True) ctr["reward"]["value"].append(reward_value) ctr["reward"]["ph"].append(reward_ph) ctr["reward"]["update"].append(reward_update) best_reward = variable_scope.get_local_variable( "best_reward_{}".format(i), initializer=failing_signal, dtype=dtypes.float32, trainable=False) ctr["best_reward"]["value"].append(best_reward) ctr["best_reward"]["update"].append( state_ops.assign( best_reward, math_ops.minimum(best_reward, reward_update))) ready_value = variable_scope.get_local_variable( "ready_{}".format(i), initializer=True, dtype=dtypes.bool, trainable=False) ready_ph = array_ops.placeholder( dtypes.bool, shape=(), name="ready_ph_{}".format(i)) ready_update = state_ops.assign(ready_value, ready_ph, use_locking=True) ctr["ready"]["value"].append(ready_value) ctr["ready"]["ph"].append(ready_ph) ctr["ready"]["update"].append(ready_update) ctr["grouping_y_preds"], ctr[ "grouping_log_probs"] = self.get_groupings() summary.histogram( "grouping_actions", array_ops.slice(ctr["grouping_y_preds"]["sample"], [0, 0], [1, array_ops.shape(self.op_embeddings)[0]])) with variable_scope.variable_scope("controller_{}".format( self.ctrl_id)): ctr["baseline"] = variable_scope.get_local_variable( "baseline", initializer=failing_signal if self.hparams.start_with_failing_signal else 0.0, dtype=dtypes.float32, trainable=False) new_baseline = self.hparams.bl_dec * ctr["baseline"] + ( 1 - self.hparams.bl_dec) * math_ops.reduce_mean( ctr["reward"]["value"]) if not self.hparams.always_update_baseline: baseline_mask = math_ops.less(ctr["reward"]["value"], failing_signal) selected_reward = array_ops.boolean_mask( ctr["reward"]["value"], baseline_mask) selected_baseline = control_flow_ops.cond( math_ops.reduce_any(baseline_mask), lambda: math_ops.reduce_mean(selected_reward), lambda: constant_op.constant(0, dtype=dtypes.float32)) ctr["pos_reward"] = selected_baseline pos_ = math_ops.less( constant_op.constant(0, dtype=dtypes.float32), selected_baseline) selected_baseline = self.hparams.bl_dec * ctr["baseline"] + ( 1 - self.hparams.bl_dec) * selected_baseline selected_baseline = control_flow_ops.cond( pos_, lambda: selected_baseline, lambda: ctr["baseline"]) new_baseline = control_flow_ops.cond( math_ops.less(self.global_step, self.hparams.stop_updating_after_steps), lambda: new_baseline, lambda: selected_baseline) ctr["baseline_update"] = state_ops.assign(ctr["baseline"], new_baseline, use_locking=True) ctr["y_preds"], ctr["log_probs"] = self.get_placements() summary.histogram("actions", ctr["y_preds"]["sample"]) mask = math_ops.less(ctr["reward"]["value"], failing_signal) ctr["loss"] = ctr["reward"]["value"] - ctr["baseline"] ctr["loss"] *= (ctr["log_probs"]["sample"] + ctr["grouping_log_probs"]["sample"]) selected_loss = array_ops.boolean_mask(ctr["loss"], mask) selected_loss = control_flow_ops.cond( math_ops.reduce_any(mask), lambda: math_ops.reduce_mean(-selected_loss), lambda: constant_op.constant(0, dtype=dtypes.float32)) ctr["loss"] = control_flow_ops.cond( math_ops.less(self.global_step, self.hparams.stop_updating_after_steps), lambda: math_ops.reduce_mean(-ctr["loss"]), lambda: selected_loss) ctr["reward_s"] = math_ops.reduce_mean(ctr["reward"]["value"]) summary.scalar("loss", ctr["loss"]) summary.scalar("avg_reward", ctr["reward_s"]) summary.scalar("best_reward_so_far", best_reward) summary.scalar( "advantage", math_ops.reduce_mean(ctr["reward"]["value"] - ctr["baseline"])) with variable_scope.variable_scope("optimizer", reuse=variable_scope.AUTO_REUSE): (ctr["train_op"], ctr["lr"], ctr["grad_norm"], ctr["grad_norms"]) = self._get_train_ops( ctr["loss"], tf_ops.get_collection(tf_ops.GraphKeys.TRAINABLE_VARIABLES), self.global_step, grad_bound=self.hparams.grad_bound, lr_init=self.hparams.lr, lr_dec=self.hparams.lr_dec, start_decay_step=self.hparams.start_decay_step, decay_steps=self.hparams.decay_steps, optimizer_type=self.hparams.optimizer_type) summary.scalar("gradnorm", ctr["grad_norm"]) summary.scalar("lr", ctr["lr"]) ctr["summary"] = summary.merge_all() ops["controller"] = ctr self.ops = ops return ops
def predicate(y): return math_ops.less(math_ops.cast(y, dtypes.int64), some_tensor)
def _cond(i, _): """Stopping condition for the while loop.""" return math_ops.less(i, num_to_sample)
def sample(self): u = tf.random_uniform(tf.shape(self.ps)) return tf.to_float(math_ops.less( u, self.ps)) # truth value of (x < y) element-wise
def training_graph(self, input_data, input_labels, random_seed, data_spec, sparse_features=None, input_weights=None): """Constructs a TF graph for training a random tree. Args: input_data: A tensor or placeholder for input data. input_labels: A tensor or placeholder for labels associated with input_data. random_seed: The random number generator seed to use for this tree. 0 means use the current time as the seed. data_spec: A data_ops.TensorForestDataSpec object specifying the original feature/columns of the data. sparse_features: A tf.SparseTensor for sparse input data. input_weights: A float tensor or placeholder holding per-input weights, or None if all inputs are to be weighted equally. Returns: The last op in the random tree training graph. """ epoch = math_ops.to_int32(get_epoch_variable()) serialized_input_spec = data_spec.SerializeToString() if input_weights is None: input_weights = [] if input_data is None: input_data = [] sparse_indices = [] sparse_values = [] sparse_shape = [] if sparse_features is not None: sparse_indices = sparse_features.indices sparse_values = sparse_features.values sparse_shape = sparse_features.dense_shape # Count extremely random stats. (node_sums, node_squares, splits_indices, splits_sums, splits_squares, totals_indices, totals_sums, totals_squares, input_leaves) = (tensor_forest_ops.count_extremely_random_stats( input_data, sparse_indices, sparse_values, sparse_shape, input_labels, input_weights, self.variables.tree, self.variables.tree_thresholds, self.variables.node_to_accumulator_map, self.variables.candidate_split_features, self.variables.candidate_split_thresholds, self.variables.start_epoch, epoch, input_spec=serialized_input_spec, num_classes=self.params.num_output_columns, regression=self.params.regression)) node_update_ops = [] node_update_ops.append( state_ops.assign_add(self.variables.node_sums, node_sums)) splits_update_ops = [] splits_update_ops.append( tensor_forest_ops.scatter_add_ndim( self.variables.candidate_split_sums, splits_indices, splits_sums)) splits_update_ops.append( tensor_forest_ops.scatter_add_ndim(self.variables.accumulator_sums, totals_indices, totals_sums)) if self.params.regression: node_update_ops.append( state_ops.assign_add(self.variables.node_squares, node_squares)) splits_update_ops.append( tensor_forest_ops.scatter_add_ndim( self.variables.candidate_split_squares, splits_indices, splits_squares)) splits_update_ops.append( tensor_forest_ops.scatter_add_ndim( self.variables.accumulator_squares, totals_indices, totals_squares)) # Sample inputs. update_indices, feature_updates, threshold_updates = ( tensor_forest_ops.sample_inputs( input_data, sparse_indices, sparse_values, sparse_shape, input_weights, self.variables.node_to_accumulator_map, input_leaves, self.variables.candidate_split_features, self.variables.candidate_split_thresholds, input_spec=serialized_input_spec, split_initializations_per_input=( self.params.split_initializations_per_input), split_sampling_random_seed=random_seed)) update_features_op = state_ops.scatter_update( self.variables.candidate_split_features, update_indices, feature_updates) update_thresholds_op = state_ops.scatter_update( self.variables.candidate_split_thresholds, update_indices, threshold_updates) # Calculate finished nodes. with ops.control_dependencies(splits_update_ops): # Passing input_leaves to finished nodes here means that nodes that # have become stale won't be deallocated until an input reaches them, # because we're trying to avoid considering every fertile node for # performance reasons. finished, stale = tensor_forest_ops.finished_nodes( input_leaves, self.variables.node_to_accumulator_map, self.variables.candidate_split_sums, self.variables.candidate_split_squares, self.variables.accumulator_sums, self.variables.accumulator_squares, self.variables.start_epoch, epoch, num_split_after_samples=self.params.split_after_samples, min_split_samples=self.params.min_split_samples, dominate_method=self.params.dominate_method, dominate_fraction=self.params.dominate_fraction) # Update leaf scores. # TODO(thomaswc): Store the leaf scores in a TopN and only update the # scores of the leaves that were touched by this batch of input. children = array_ops.squeeze(array_ops.slice(self.variables.tree, [0, 0], [-1, 1]), squeeze_dims=[1]) is_leaf = math_ops.equal(constants.LEAF_NODE, children) leaves = math_ops.to_int32( array_ops.squeeze(array_ops.where(is_leaf), squeeze_dims=[1])) non_fertile_leaves = array_ops.boolean_mask( leaves, math_ops.less( array_ops.gather(self.variables.node_to_accumulator_map, leaves), 0)) # TODO(gilberth): It should be possible to limit the number of non # fertile leaves we calculate scores for, especially since we can only take # at most array_ops.shape(finished)[0] of them. with ops.control_dependencies(node_update_ops): sums = array_ops.gather(self.variables.node_sums, non_fertile_leaves) if self.params.regression: squares = array_ops.gather(self.variables.node_squares, non_fertile_leaves) non_fertile_leaf_scores = self._variance(sums, squares) else: non_fertile_leaf_scores = self._weighted_gini(sums) # Calculate best splits. with ops.control_dependencies(splits_update_ops): split_indices = tensor_forest_ops.best_splits( finished, self.variables.node_to_accumulator_map, self.variables.candidate_split_sums, self.variables.candidate_split_squares, self.variables.accumulator_sums, self.variables.accumulator_squares, regression=self.params.regression) # Grow tree. with ops.control_dependencies( [update_features_op, update_thresholds_op, non_fertile_leaves.op]): (tree_update_indices, tree_children_updates, tree_threshold_updates, new_eot) = (tensor_forest_ops.grow_tree( self.variables.end_of_tree, self.variables.node_to_accumulator_map, finished, split_indices, self.variables.candidate_split_features, self.variables.candidate_split_thresholds)) tree_update_op = state_ops.scatter_update(self.variables.tree, tree_update_indices, tree_children_updates) thresholds_update_op = state_ops.scatter_update( self.variables.tree_thresholds, tree_update_indices, tree_threshold_updates) # TODO(thomaswc): Only update the epoch on the new leaves. new_epoch_updates = epoch * array_ops.ones_like( tree_threshold_updates, dtype=dtypes.int32) epoch_update_op = state_ops.scatter_update( self.variables.start_epoch, tree_update_indices, new_epoch_updates) # Update fertile slots. with ops.control_dependencies([tree_update_op]): (n2a_map_updates, a2n_map_updates, accumulators_cleared, accumulators_allocated) = (tensor_forest_ops.update_fertile_slots( finished, non_fertile_leaves, non_fertile_leaf_scores, self.variables.end_of_tree, self.variables.accumulator_sums, self.variables.node_to_accumulator_map, stale, self.variables.node_sums, regression=self.params.regression)) # Ensure end_of_tree doesn't get updated until UpdateFertileSlots has # used it to calculate new leaves. with ops.control_dependencies([n2a_map_updates.op]): eot_update_op = state_ops.assign(self.variables.end_of_tree, new_eot) updates = [] updates.append(eot_update_op) updates.append(tree_update_op) updates.append(thresholds_update_op) updates.append(epoch_update_op) updates.append( state_ops.scatter_update(self.variables.node_to_accumulator_map, n2a_map_updates[0], n2a_map_updates[1])) updates.append( state_ops.scatter_update(self.variables.accumulator_to_node_map, a2n_map_updates[0], a2n_map_updates[1])) cleared_and_allocated_accumulators = array_ops.concat( [accumulators_cleared, accumulators_allocated], 0) # Calculate values to put into scatter update for candidate counts. # Candidate split counts are always reset back to 0 for both cleared # and allocated accumulators. This means some accumulators might be doubly # reset to 0 if the were released and not allocated, then later allocated. split_values = array_ops.tile( array_ops.expand_dims( array_ops.expand_dims( array_ops.zeros_like(cleared_and_allocated_accumulators, dtype=dtypes.float32), 1), 2), [ 1, self.params.num_splits_to_consider, self.params.num_output_columns ]) updates.append( state_ops.scatter_update(self.variables.candidate_split_sums, cleared_and_allocated_accumulators, split_values)) if self.params.regression: updates.append( state_ops.scatter_update( self.variables.candidate_split_squares, cleared_and_allocated_accumulators, split_values)) # Calculate values to put into scatter update for total counts. total_cleared = array_ops.tile( array_ops.expand_dims( math_ops.negative( array_ops.ones_like(accumulators_cleared, dtype=dtypes.float32)), 1), [1, self.params.num_output_columns]) total_reset = array_ops.tile( array_ops.expand_dims( array_ops.zeros_like(accumulators_allocated, dtype=dtypes.float32), 1), [1, self.params.num_output_columns]) accumulator_updates = array_ops.concat([total_cleared, total_reset], 0) updates.append( state_ops.scatter_update(self.variables.accumulator_sums, cleared_and_allocated_accumulators, accumulator_updates)) if self.params.regression: updates.append( state_ops.scatter_update(self.variables.accumulator_squares, cleared_and_allocated_accumulators, accumulator_updates)) # Calculate values to put into scatter update for candidate splits. split_features_updates = array_ops.tile( array_ops.expand_dims( math_ops.negative( array_ops.ones_like(cleared_and_allocated_accumulators)), 1), [1, self.params.num_splits_to_consider]) updates.append( state_ops.scatter_update(self.variables.candidate_split_features, cleared_and_allocated_accumulators, split_features_updates)) updates += self.finish_iteration() return control_flow_ops.group(*updates)
def accumulation_function(counter, lim, accum): while math_ops.less(counter, lim): accum.assign(accum * 2.0) counter.assign_add(1)
def training_graph(self, input_data, input_labels, num_trainers=1, trainer_id=0, **tree_kwargs): """Constructs a TF graph for training a random forest. Args: input_data: A tensor or dict of string->Tensor for input data. input_labels: A tensor or placeholder for labels associated with input_data. num_trainers: Number of parallel trainers to split trees among. trainer_id: Which trainer this instance is. **tree_kwargs: Keyword arguments passed to each tree's training_graph. Returns: The last op in the random forest training graph. Raises: NotImplementedError: If trying to use bagging with sparse features. """ processed_dense_features, processed_sparse_features, data_spec = ( data_ops.ParseDataTensorOrDict(input_data)) if input_labels is not None: labels = data_ops.ParseLabelTensorOrDict(input_labels) data_spec = data_spec or self.get_default_data_spec(input_data) tree_graphs = [] trees_per_trainer = self.params.num_trees / num_trainers tree_start = int(trainer_id * trees_per_trainer) tree_end = int((trainer_id + 1) * trees_per_trainer) for i in range(tree_start, tree_end): logging.info('training graph for tree: %d' % i) with ops.device(self.device_assigner.get_device(i)): seed = self.params.base_random_seed if seed != 0: seed += i # If using bagging, randomly select some of the input. tree_data = processed_dense_features tree_labels = labels if self.params.bagging_fraction < 1.0: # TODO(gilberth): Support bagging for sparse features. if processed_sparse_features is not None: raise NotImplementedError( 'Bagging not supported with sparse features.') # TODO(thomaswc): This does sampling without replacment. Consider # also allowing sampling with replacement as an option. batch_size = array_ops.strided_slice( array_ops.shape(processed_dense_features), [0], [1]) r = random_ops.random_uniform(batch_size, seed=seed) mask = math_ops.less( r, array_ops.ones_like(r) * self.params.bagging_fraction) gather_indices = array_ops.squeeze(array_ops.where(mask), squeeze_dims=[1]) # TODO(thomaswc): Calculate out-of-bag data and labels, and store # them for use in calculating statistics later. tree_data = array_ops.gather(processed_dense_features, gather_indices) tree_labels = array_ops.gather(labels, gather_indices) if self.params.bagged_features: if processed_sparse_features is not None: raise NotImplementedError( 'Feature bagging not supported with sparse features.' ) tree_data = self._bag_features(i, tree_data) initialization = self.trees[i].tree_initialization() with ops.control_dependencies([initialization]): tree_graphs.append(self.trees[i].training_graph( tree_data, tree_labels, seed, data_spec=data_spec, sparse_features=processed_sparse_features, **tree_kwargs)) return control_flow_ops.group(*tree_graphs, name='train')
def f(start): c = lambda x: math_ops.less(x, 13.0) b = lambda x: math_ops.add(x, 1.0) return control_flow_ops.while_loop(c, b, [start])
def rotate_transpose(x, shift, name="rotate_transpose"): """Circularly moves dims left or right. Effectively identical to: ```python numpy.transpose(x, numpy.roll(numpy.arange(len(x.shape)), shift)) ``` When `validate_args=False` additional graph-runtime checks are performed. These checks entail moving data from to GPU to CPU. Example: ```python x = tf.random_normal([1, 2, 3, 4]) # Tensor of shape [1, 2, 3, 4]. rotate_transpose(x, -1).shape == [2, 3, 4, 1] rotate_transpose(x, -2).shape == [3, 4, 1, 2] rotate_transpose(x, 1).shape == [4, 1, 2, 3] rotate_transpose(x, 2).shape == [3, 4, 1, 2] rotate_transpose(x, 7).shape == rotate_transpose(x, 3).shape # [2, 3, 4, 1] rotate_transpose(x, -7).shape == rotate_transpose(x, -3).shape # [4, 1, 2, 3] ``` Args: x: `Tensor`. shift: `Tensor`. Number of dimensions to transpose left (shift<0) or transpose right (shift>0). name: Python `str`. The name to give this op. Returns: rotated_x: Input `Tensor` with dimensions circularly rotated by shift. Raises: TypeError: if shift is not integer type. """ with ops.name_scope(name, values=[x, shift]): x = ops.convert_to_tensor(x, name="x") shift = ops.convert_to_tensor(shift, name="shift") # We do not assign back to preserve constant-ness. check_ops.assert_integer(shift) shift_value_static = tensor_util.constant_value(shift) ndims = x.get_shape().ndims if ndims is not None and shift_value_static is not None: if ndims < 2: return x shift_value_static = np.sign(shift_value_static) * ( abs(shift_value_static) % ndims) if shift_value_static == 0: return x perm = np.roll(np.arange(ndims), shift_value_static) return array_ops.transpose(x, perm=perm) else: # Consider if we always had a positive shift, and some specified # direction. # When shifting left we want the new array: # last(x, n-shift) + first(x, shift) # and if shifting right then we want: # last(x, shift) + first(x, n-shift) # Observe that last(a) == slice(a, n) and first(a) == slice(0, a). # Also, we can encode direction and shift as one: direction * shift. # Combining these facts, we have: # a = cond(shift<0, -shift, n-shift) # last(x, n-a) + first(x, a) == x[a:n] + x[0:a] # Finally, we transform shift by modulo length so it can be specified # independently from the array upon which it operates (like python). ndims = array_ops.rank(x) shift = array_ops.where(math_ops.less(shift, 0), math_ops.mod(-shift, ndims), ndims - math_ops.mod(shift, ndims)) first = math_ops.range(0, shift) last = math_ops.range(shift, ndims) perm = array_ops.concat([last, first], 0) return array_ops.transpose(x, perm=perm)
def apply_gradients(self, grads_and_vars, global_step=None, name=None): """Apply gradients to variables. This contains most of the synchronization implementation and also wraps the apply_gradients() from the real optimizer. Args: grads_and_vars: List of (gradient, variable) pairs as returned by compute_gradients(). global_step: Optional Variable to increment by one after the variables have been updated. name: Optional name for the returned operation. Default to the name passed to the Optimizer constructor. Returns: train_op: The op to dequeue a token so the replicas can exit this batch and start the next one. This is executed by each replica. Raises: ValueError: If the grads_and_vars is empty. ValueError: If global step is not provided, the staleness cannot be checked. """ if not grads_and_vars: raise ValueError("Must supply at least one variable") if global_step is None: raise ValueError("Global step is required to check staleness") self._global_step = global_step train_ops = [] aggregated_grad = [] inputs = [] var_list = [] for x in grads_and_vars: inputs.extend(list(x)) with ops.device(global_step.device): self._local_steps = variables.Variable(array_ops.zeros( [self._total_num_replicas], dtype=global_step.dtype), trainable=False, name="local_steps") # Check staleness. Note that this has to be ref(), otherwise identity will # be accessed and it will be old values. local_step = array_ops.slice( self._local_steps._ref(), # pylint: disable=protected-access array_ops.reshape(self._replica_id, (1, )), [1], name="get_local_step") local_step = array_ops.reshape(local_step, ()) is_stale = math_ops.less(local_step, global_step) with ops.name_scope(name, self._name, inputs) as name: for grad, var in grads_and_vars: var_list.append(var) with ops.device(var.device): if isinstance(grad, ops.Tensor): gradient_queue = (data_flow_ops.FIFOQueue( self._tokens_per_step * 2, grad.dtype, shapes=var.get_shape(), shared_name=var.name)) self._one_element_queue_list.append( (gradient_queue, var.device)) train_ops.append(gradient_queue.enqueue([grad])) # Aggregate all gradients gradients = gradient_queue.dequeue_many( self._replicas_to_aggregate) aggregated_grad.append( math_ops.reduce_sum(gradients, [0])) elif grad is None: aggregated_grad.append(None) # pass-through. else: if not isinstance(grad, ops.IndexedSlices): raise ValueError("Unknown grad type!") aggregated_grad.append( self._aggregate_sparse_grad(grad, var, train_ops)) aggregated_grads_and_vars = zip(aggregated_grad, var_list) # sync_op will be assigned to the same device as the global step. with ops.device(global_step.device), ops.name_scope(""): update_op = self._opt.apply_gradients( aggregated_grads_and_vars, global_step) # Create token queue. with ops.device(global_step.device), ops.name_scope(""): sync_token_queue = (data_flow_ops.FIFOQueue( -1, global_step.dtype.base_dtype, shapes=(), shared_name="sync_token_q")) self._sync_token_queue = sync_token_queue # dummy_queue is passed to the queue runner. Don't use the real queues # because the queue runner doesn't automatically reopen it once it # closed queues in PS devices. dummy_queue = (data_flow_ops.FIFOQueue( 1, types_pb2.DT_INT32, shapes=(), shared_name="dummy_queue")) # Clear all the gradients queues in case there are stale gradients. clear_queue_ops = [] with ops.control_dependencies([update_op]): for queue, dev in self._one_element_queue_list: with ops.device(dev): stale_grads = queue.dequeue_many(queue.size()) clear_queue_ops.append(stale_grads) for queue, dev in self._sparse_grad_queues_and_devs: with ops.device(dev): _, stale_indices = queue.dequeue_many(queue.size()) clear_queue_ops.append(stale_indices) with ops.device(global_step.device): self._clean_up_op = control_flow_ops.abort( error_msg="From sync_replicas") # According to the staleness, select between the enqueue op (real_grad) # or no-op (no_op_grad). Effectively dropping all the stale gradients. no_op_grad = lambda: [ control_flow_ops.no_op(name="no_grad_enqueue") ] real_grad = lambda: [control_flow_ops.group(*train_ops)] final_train_ops = control_flow_ops.cond(is_stale, no_op_grad, real_grad) with ops.device(global_step.device), ops.name_scope(""): # Replicas have to wait until they can get a token from the token queue. with ops.control_dependencies([final_train_ops]): token = sync_token_queue.dequeue() train_op = state_ops.scatter_update(self._local_steps, self._replica_id, token, name=name) with ops.control_dependencies(clear_queue_ops): # Sync_op needs to insert tokens to the token queue at the end of the # step so the replicas can fetch them to start the next step. # Note that ref() is used to avoid reading from the identity with old # the step. tokens = array_ops.fill([self._tokens_per_step], global_step._ref()) # pylint: disable=protected-access sync_op = sync_token_queue.enqueue_many((tokens, )) if self._variable_averages is not None: with ops.control_dependencies([sync_op ]), ops.name_scope(""): sync_op = self._variable_averages.apply( self._variables_to_average) self._chief_queue_runner = queue_runner.QueueRunner( dummy_queue, [sync_op]) self._gradients_applied = True return train_op
def batch_execute(global_step, thunks, batch_size, name=None): """Executes a subset of ops per global step. Given a list of thunks, each of which produces a single stateful op, ensures that exactly 'batch_size' ops are run per global step. Ops are scheduled in a round-robin fashion. For example, with 3 ops global_step | op0 | op1 | op2 ------------+-----+-----+----- 0 | x | x | ------------+-----+-----+----- 1 | x | | x ------------+-----+-----+----- 2 | | x | x ------------+-----+-----+----- 3 | x | x | ------------+-----+-----+----- 4 | x | | x Does not guarantee order of op execution within a single global step. Args: global_step: Tensor indicating time. Determines which ops run. thunks: List of thunks. Each thunk encapsulates one op. Return values are ignored. batch_size: int. Number of ops to execute per global_step. name: string or None. Name scope for newly added ops. Returns: List of ops. Exactly 'batch_size' ops are guaranteed to have an effect every global step. """ def true_fn(thunk): """Ensures thunk is executed and returns an Op (not a Tensor).""" def result(): with ops.control_dependencies([thunk()]): return control_flow_ops.no_op() return result def false_fn(_): """Executes a no-op.""" def result(): return control_flow_ops.no_op() return result with ops.name_scope(name, "batch_execute"): true_fns = [true_fn(thunk) for thunk in thunks] false_fns = [false_fn(thunk) for thunk in thunks] num_thunks = len(thunks) conditions = [ math_ops.less( math_ops.mod(batch_size - 1 + global_step * batch_size - j, num_thunks), batch_size) for j in range(num_thunks) ] result = [ control_flow_ops.cond(condition, true_fn, false_fn) for (condition, true_fn, false_fn) in zip(conditions, true_fns, false_fns) ] return result
def matrix_exponential(input, name=None): # pylint: disable=redefined-builtin r"""Computes the matrix exponential of one or more square matrices. exp(A) = \sum_{n=0}^\infty A^n/n! The exponential is computed using a combination of the scaling and squaring method and the Pade approximation. Details can be found in: Nicholas J. Higham, "The scaling and squaring method for the matrix exponential revisited," SIAM J. Matrix Anal. Applic., 26:1179-1193, 2005. The input is a tensor of shape `[..., M, M]` whose inner-most 2 dimensions form square matrices. The output is a tensor of the same shape as the input containing the exponential for all input submatrices `[..., :, :]`. Args: input: A `Tensor`. Must be `float16`, `float32`, `float64`, `complex64`, or `complex128` with shape `[..., M, M]`. name: A name to give this `Op` (optional). Returns: the matrix exponential of the input. Raises: ValueError: An unsupported type is provided as input. @compatibility(scipy) Equivalent to scipy.linalg.expm @end_compatibility """ with ops.name_scope(name, 'matrix_exponential', [input]): matrix = ops.convert_to_tensor(input, name='input') if matrix.shape[-2:] == [0, 0]: return matrix batch_shape = matrix.shape[:-2] if not batch_shape.is_fully_defined(): batch_shape = array_ops.shape(matrix)[:-2] # reshaping the batch makes the where statements work better matrix = array_ops.reshape( matrix, array_ops.concat(([-1], array_ops.shape(matrix)[-2:]), axis=0)) l1_norm = math_ops.reduce_max( math_ops.reduce_sum( math_ops.abs(matrix), axis=array_ops.size(array_ops.shape(matrix)) - 2), axis=-1) const = lambda x: constant_op.constant(x, l1_norm.dtype) def _nest_where(vals, cases): assert len(vals) == len(cases) - 1 if len(vals) == 1: return array_ops.where( math_ops.less(l1_norm, const(vals[0])), cases[0], cases[1]) else: return array_ops.where( math_ops.less(l1_norm, const(vals[0])), cases[0], _nest_where(vals[1:], cases[1:])) if matrix.dtype in [dtypes.float16, dtypes.float32, dtypes.complex64]: maxnorm = const(3.925724783138660) squarings = math_ops.maximum( math_ops.floor( math_ops.log(l1_norm / maxnorm) / math_ops.log(const(2.0))), 0) u3, v3 = _matrix_exp_pade3(matrix) u5, v5 = _matrix_exp_pade5(matrix) u7, v7 = _matrix_exp_pade7(matrix / math_ops.cast( math_ops.pow(const(2.0), squarings), matrix.dtype)[..., array_ops.newaxis, array_ops.newaxis]) conds = (4.258730016922831e-001, 1.880152677804762e+000) u = _nest_where(conds, (u3, u5, u7)) v = _nest_where(conds, (v3, v5, v7)) elif matrix.dtype in [dtypes.float64, dtypes.complex128]: maxnorm = const(5.371920351148152) squarings = math_ops.maximum( math_ops.floor( math_ops.log(l1_norm / maxnorm) / math_ops.log(const(2.0))), 0) u3, v3 = _matrix_exp_pade3(matrix) u5, v5 = _matrix_exp_pade5(matrix) u7, v7 = _matrix_exp_pade7(matrix) u9, v9 = _matrix_exp_pade9(matrix) u13, v13 = _matrix_exp_pade13(matrix / math_ops.cast( math_ops.pow(const(2.0), squarings), matrix.dtype)[..., array_ops.newaxis, array_ops.newaxis]) conds = (1.495585217958292e-002, 2.539398330063230e-001, 9.504178996162932e-001, 2.097847961257068e+000) u = _nest_where(conds, (u3, u5, u7, u9, u13)) v = _nest_where(conds, (v3, v5, v7, v9, v13)) else: raise ValueError('tf.linalg.expm does not support matrices of type %s' % matrix.dtype) numer = u + v denom = -u + v result = linalg_ops.matrix_solve(denom, numer) max_squarings = math_ops.reduce_max(squarings) i = const(0.0) c = lambda i, r: math_ops.less(i, max_squarings) def b(i, r): return i + 1, array_ops.where( math_ops.less(i, squarings), math_ops.matmul(r, r), r) _, result = control_flow_ops.while_loop(c, b, [i, result]) if not matrix.shape.is_fully_defined(): return array_ops.reshape( result, array_ops.concat((batch_shape, array_ops.shape(result)[-2:]), axis=0)) return array_ops.reshape(result, batch_shape.concatenate(result.shape[-2:]))
def condition(v, d, i, r): del v, d, r # unused vars by condition return math_ops.less(i, 100)
def assert_near(x, y, rtol=None, atol=None, data=None, summarize=None, message=None, name=None): """Assert the condition `x` and `y` are close element-wise. Example of adding a dependency to an operation: ```python with tf.control_dependencies([tf.assert_near(x, y)]): output = tf.reduce_sum(x) ``` This condition holds if for every pair of (possibly broadcast) elements `x[i]`, `y[i]`, we have ```tf.abs(x[i] - y[i]) <= atol + rtol * tf.abs(y[i])```. If both `x` and `y` are empty, this is trivially satisfied. The default `atol` and `rtol` is `10 * eps`, where `eps` is the smallest representable positive number such that `1 + eps != eps`. This is about `1.2e-6` in `32bit`, `2.22e-15` in `64bit`, and `0.00977` in `16bit`. See `numpy.finfo`. Args: x: Float or complex `Tensor`. y: Float or complex `Tensor`, same `dtype` as, and broadcastable to, `x`. rtol: `Tensor`. Same `dtype` as, and broadcastable to, `x`. The relative tolerance. Default is `10 * eps`. atol: `Tensor`. Same `dtype` as, and broadcastable to, `x`. The absolute tolerance. Default is `10 * eps`. data: The tensors to print out if the condition is False. Defaults to error message and first few entries of `x`, `y`. summarize: Print this many entries of each tensor. message: A string to prefix to the default message. name: A name for this operation (optional). Defaults to "assert_near". Returns: Op that raises `InvalidArgumentError` if `x` and `y` are not close enough. @compatibility(numpy) Similar to `numpy.assert_allclose`, except tolerance depends on data type. This is due to the fact that `TensorFlow` is often used with `32bit`, `64bit`, and even `16bit` data. @end_compatibility """ message = message or '' with ops.name_scope(name, 'assert_near', [x, y, rtol, atol, data]): x = ops.convert_to_tensor(x, name='x') y = ops.convert_to_tensor(y, name='y', dtype=x.dtype) eps = np.finfo(x.dtype.as_numpy_dtype).eps rtol = 10 * eps if rtol is None else rtol atol = 10 * eps if atol is None else atol rtol = ops.convert_to_tensor(rtol, name='rtol', dtype=x.dtype) atol = ops.convert_to_tensor(atol, name='atol', dtype=x.dtype) if context.in_eager_mode(): x_name = _shape_and_dtype_str(x) y_name = _shape_and_dtype_str(y) else: x_name = x.name y_name = y.name if data is None: data = [ message, 'x and y not equal to tolerance rtol = %s, atol = %s' % (rtol, atol), 'x (%s) = ' % x_name, x, 'y (%s) = ' % y_name, y ] tol = atol + rtol * math_ops.abs(y) diff = math_ops.abs(x - y) condition = math_ops.reduce_all(math_ops.less(diff, tol)) return control_flow_ops.Assert(condition, data, summarize=summarize)
def map_fn(x): c = lambda i: math_ops.less(i, 10) b = lambda i: math_ops.add(i, 1) return control_flow_ops.while_loop(c, b, [x])
def __lt__(self, other): return math_ops.less(self, other)
def _testScopedExport(self, test_dir, exported_filenames): graph = ops.Graph() with graph.as_default(): # Creates an inference graph. # Hidden 1 colocate_constraint = constant_op.constant(1.2, name="constraint") images = constant_op.constant( 1.2, dtypes.float32, shape=[100, 28], name="images") with ops.name_scope("hidden1"): with graph.colocate_with(colocate_constraint.op): weights1 = variables.Variable( random_ops.truncated_normal( [28, 128], stddev=1.0 / math.sqrt(float(28))), name="weights") # The use of control_flow_ops.cond here is purely for adding test # coverage the save and restore of control flow context (which doesn't # make any sense here from a machine learning perspective). The typical # biases is a simple Variable without the conditions. biases1 = variables.Variable( control_flow_ops.cond( math_ops.less(random.random(), 0.5), lambda: array_ops.ones([128]), lambda: array_ops.zeros([128])), name="biases") hidden1 = nn_ops.relu(math_ops.matmul(images, weights1) + biases1) # Hidden 2 with ops.name_scope("hidden2"): weights2 = variables.Variable( random_ops.truncated_normal( [128, 32], stddev=1.0 / math.sqrt(float(128))), name="weights") # The use of control_flow_ops.while_loop here is purely for adding test # coverage the save and restore of control flow context (which doesn't # make any sense here from a machine learning perspective). The typical # biases is a simple Variable without the conditions. def loop_cond(it, _): return it < 2 def loop_body(it, biases2): biases2 += constant_op.constant(0.1, shape=[32]) return it + 1, biases2 _, biases2 = control_flow_ops.while_loop( loop_cond, loop_body, [ constant_op.constant(0), variables.Variable( array_ops.zeros([32]), name="biases") ]) hidden2 = nn_ops.relu(math_ops.matmul(hidden1, weights2) + biases2) # Linear with ops.name_scope("softmax_linear"): weights3 = variables.Variable( random_ops.truncated_normal( [32, 10], stddev=1.0 / math.sqrt(float(32))), name="weights") biases3 = variables.Variable(array_ops.zeros([10]), name="biases") logits = math_ops.matmul(hidden2, weights3) + biases3 ops.add_to_collection("logits", logits) # Exports each sub-graph. # Exports the first one with unbound_inputs_col_name set to default. orig_meta_graph1, var_list = meta_graph.export_scoped_meta_graph( filename=os.path.join(test_dir, exported_filenames[0]), graph=ops.get_default_graph(), export_scope="hidden1") self.assertEqual(["biases:0", "weights:0"], sorted(var_list.keys())) var_names = [v.name for _, v in var_list.items()] self.assertEqual(["hidden1/biases:0", "hidden1/weights:0"], sorted(var_names)) # Exports the rest with no unbound_inputs_col_name. orig_meta_graph2, _ = meta_graph.export_scoped_meta_graph( filename=os.path.join(test_dir, exported_filenames[1]), graph=ops.get_default_graph(), export_scope="hidden2", unbound_inputs_col_name=None) orig_meta_graph3, _ = meta_graph.export_scoped_meta_graph( filename=os.path.join(test_dir, exported_filenames[2]), graph=ops.get_default_graph(), export_scope="softmax_linear", unbound_inputs_col_name=None) return [orig_meta_graph1, orig_meta_graph2, orig_meta_graph3]
def _get_train_ops(self, loss, tf_variables, global_step, grad_bound=1.25, lr_init=1e-3, lr_dec=0.9, start_decay_step=10000, decay_steps=100, optimizer_type="adam"): """Loss optimizer. Args: loss: scalar tf tensor tf_variables: list of training variables, typically tf.trainable_variables() global_step: global_step grad_bound: max gradient norm lr_init: initial learning rate lr_dec: leaning rate decay coefficient start_decay_step: start decaying learning rate after this many steps decay_steps: apply decay rate factor at this step intervals optimizer_type: optimizer type should be either adam or sgd Returns: train_op: training op learning_rate: scalar learning rate tensor grad_norm: l2 norm of the gradient vector all_grad_norms: l2 norm of each component """ lr_gstep = global_step - start_decay_step def f1(): return constant_op.constant(lr_init) def f2(): return learning_rate_decay.exponential_decay( lr_init, lr_gstep, decay_steps, lr_dec, True) learning_rate = control_flow_ops.cond(math_ops.less( global_step, start_decay_step), f1, f2, name="learning_rate") if optimizer_type == "adam": opt = adam.AdamOptimizer(learning_rate) elif optimizer_type == "sgd": opt = gradient_descent.GradientDescentOptimizer(learning_rate) grads_and_vars = opt.compute_gradients(loss, tf_variables) grad_norm = clip_ops.global_norm([g for g, v in grads_and_vars]) all_grad_norms = {} clipped_grads = [] clipped_rate = math_ops.maximum(grad_norm / grad_bound, 1.0) for g, v in grads_and_vars: if g is not None: if isinstance(g, tf_ops.IndexedSlices): clipped = g.values / clipped_rate norm_square = math_ops.reduce_sum(clipped * clipped) clipped = tf_ops.IndexedSlices(clipped, g.indices) else: clipped = g / clipped_rate norm_square = math_ops.reduce_sum(clipped * clipped) all_grad_norms[v.name] = math_ops.sqrt(norm_square) clipped_grads.append((clipped, v)) train_op = opt.apply_gradients(clipped_grads, global_step) return train_op, learning_rate, grad_norm, all_grad_norms
def filter_fn(keys, examples_json): del keys serialized = parsing_ops.decode_json_example(examples_json) examples = parsing_ops.parse_example(serialized, features) return math_ops.less(examples["age"], 2)