def testMap_Scoped(self): with self.cached_session() as sess: def double_scoped(x): """2x with a dummy 2 that is scoped.""" with variable_scope.variable_scope("body"): # Dummy variable, just to check that scoping works as intended. two = variable_scope.get_variable( "two", [], dtype=dtypes.int32, initializer=init_ops.constant_initializer(2)) return math_ops.multiply(x, two) with variable_scope.variable_scope("root") as varscope: elems = constant_op.constant([1, 2, 3, 4, 5, 6], name="data") doubles = np.array([2 * x for x in [1, 2, 3, 4, 5, 6]]) r = functional_ops.map_fn(double_scoped, elems) # Check that we have the one variable we asked for here. self.assertEqual(len(variables.trainable_variables()), 1) self.assertEqual(variables.trainable_variables()[0].name, "root/body/two:0") sess.run([variables.global_variables_initializer()]) self.assertAllEqual(doubles, self.evaluate(r)) # Now let's reuse our single variable. varscope.reuse_variables() r = functional_ops.map_fn(double_scoped, elems) self.assertEqual(len(variables.trainable_variables()), 1) self.assertAllEqual(doubles, self.evaluate(r))
def testMapSparseTensor(self): with self.cached_session(): with self.assertRaises(TypeError): functional_ops.map_fn( lambda x: x, sparse_tensor.SparseTensor( indices=[[0, 0], [0, 1], [1, 0]], values=constant_op.constant([0, 1, 2]), dense_shape=[2, 2]))
def testMap_MultiOutputMismatchedDtype(self): nums = np.array([1, 2, 3, 4, 5, 6]) with self.assertRaisesRegexp( TypeError, r"two structures don't have the same nested structure"): # lambda emits tuple, but dtype is a list functional_ops.map_fn( lambda x: ((x + 3) * 2, -(x + 3) * 2), nums, dtype=[dtypes.int64, dtypes.int64])
def compute_activations(elems): return functional_ops.map_fn(fn=classifier_fn, elems=elems, parallel_iterations=1, back_prop=False, swap_memory=True, name='RunClassifier')
def testMap_SimpleNotTensor(self): with self.test_session(): nums = np.array([1, 2, 3, 4, 5, 6]) r = functional_ops.map_fn( lambda x: math_ops.multiply(math_ops.add(x, 3), 2), nums) self.assertAllEqual( np.array([(x + 3) * 2 for x in nums]), self.evaluate(r))
def _sample_n(self, n, seed=None): n_draws = math_ops.cast(self.total_count, dtype=dtypes.int32) k = self.event_shape_tensor()[0] # broadcast the total_count and logits to same shape n_draws = array_ops.ones_like( self.logits[..., 0], dtype=n_draws.dtype) * n_draws logits = array_ops.ones_like( n_draws[..., array_ops.newaxis], dtype=self.logits.dtype) * self.logits # flatten the total_count and logits flat_logits = array_ops.reshape(logits, [-1, k]) # [B1B2...Bm, k] flat_ndraws = n * array_ops.reshape(n_draws, [-1]) # [B1B2...Bm] # computes each total_count and logits situation by map_fn def _sample_single(args): logits, n_draw = args[0], args[1] # [K], [] x = random_ops.multinomial(logits[array_ops.newaxis, ...], n_draw, seed) # [1, n*n_draw] x = array_ops.reshape(x, shape=[n, -1]) # [n, n_draw] x = math_ops.reduce_sum(array_ops.one_hot(x, depth=k), axis=-2) # [n, k] return x x = functional_ops.map_fn( _sample_single, [flat_logits, flat_ndraws], dtype=self.dtype) # [B1B2...Bm, n, k] # reshape the results to proper shape x = array_ops.transpose(x, perm=[1, 0, 2]) final_shape = array_ops.concat([[n], self.batch_shape_tensor(), [k]], 0) x = array_ops.reshape(x, final_shape) # [n, B1, B2,..., Bm, k] return x
def testMap_Simple(self): nums = [1, 2, 3, 4, 5, 6] elems = constant_op.constant(nums, name="data") r = functional_ops.map_fn( lambda x: math_ops.multiply(math_ops.add(x, 3), 2), elems) self.assertAllEqual( np.array([(x + 3) * 2 for x in nums]), self.evaluate(r))
def ctc_unique_labels(labels, name=None): """Get unique labels and indices for batched labels for tf.nn.ctc_loss. For use with tf.nn.ctc_loss_v2 optional argument `unique`: This op can be used to preprocess labels in input pipeline to for better speed/memory use computing the ctc loss on TPU. Example: ctc_unique_labels([[3, 4, 4, 3]]) -> unique labels padded with 0: [[3, 4, 0, 0]] indices of original labels in unique: [0, 1, 1, 0] Args: labels: tensor of shape [batch_size, max_label_length] padded with 0. name: A name for this `Op`. Defaults to "ctc_unique_labels". Returns: tuple of - unique labels, tensor of shape `[batch_size, max_label_length]` - indices into unique labels, shape `[batch_size, max_label_length]` """ with ops.name_scope(name, "ctc_unique_labels", [labels]): labels = ops.convert_to_tensor(labels, name="labels") def _unique(x): u = array_ops.unique(x) y = array_ops.pad( u.y, [[0, _get_dim(u.idx, 0) - _get_dim(u.y, 0)]]) y = math_ops.cast(y, dtypes.int64) return [y, u.idx] return functional_ops.map_fn( _unique, labels, dtype=[dtypes.int64, dtypes.int32])
def sparse_boolean_mask(sparse_tensor, mask, name="sparse_boolean_mask"): """Boolean mask for `SparseTensor`s. Args: sparse_tensor: a `SparseTensor`. mask: a 1D boolean dense`Tensor` whose length is equal to the 0th dimension of `sparse_tensor`. name: optional name for this operation. Returns: A `SparseTensor` that contains row `k` of `sparse_tensor` iff `mask[k]` is `True`. """ # TODO(jamieas): consider mask dimension > 1 for symmetry with `boolean_mask`. with ops.op_scope([sparse_tensor, mask], name): mask = ops.convert_to_tensor(mask) mask_rows = array_ops.where(mask) first_indices = array_ops.squeeze(array_ops.slice(sparse_tensor.indices, [0, 0], [-1, 1])) # Identify indices corresponding to the rows identified by mask_rows. sparse_entry_matches = functional_ops.map_fn( lambda x: math_ops.equal(first_indices, x), mask_rows, dtype=dtypes.bool) # Combine the rows of index_matches to form a mask for the sparse indices # and values. to_retain = array_ops.reshape( functional_ops.foldl(math_ops.logical_or, sparse_entry_matches), [-1]) return sparse_ops.sparse_retain(sparse_tensor, to_retain)
def compress(self, inputs): """Compress inputs and store their binary representations into strings. Args: inputs: `Tensor` with values to be compressed. Returns: String `Tensor` vector containing the compressed representation of each batch element of `inputs`. """ with ops.name_scope(self._name_scope()): inputs = ops.convert_to_tensor(inputs) if not self.built: # Check input assumptions set before layer building, e.g. input rank. self._assert_input_compatibility(inputs) if self.dtype is None: self._dtype = inputs.dtype.base_dtype.name self.build(inputs.shape) # Check input assumptions set after layer building, e.g. input shape. if not context.executing_eagerly(): self._assert_input_compatibility(inputs) ndim = self.input_spec.ndim channel_axis = self._channel_axis(ndim) # Tuple of slices for expanding dimensions of tensors below. slices = ndim * [None] + [slice(None)] slices[channel_axis] = slice(None) slices = tuple(slices) # Expand dimensions of CDF to input dimensions, keeping the channels along # the right dimension. cdf = self._quantized_cdf[slices[1:]] num_levels = array_ops.shape(cdf)[-1] - 1 # Bring inputs to the right range by centering the range on the medians. half = constant_op.constant(.5, dtype=self.dtype) medians = array_ops.squeeze(self._medians, [1, 2]) offsets = (math_ops.cast(num_levels // 2, self.dtype) + half) - medians # Expand offsets to input dimensions and add to inputs. values = inputs + offsets[slices[:-1]] # Clip to range and cast to integers. Because we have added .5 above, and # all values are positive, the cast effectively implements rounding. values = math_ops.maximum(values, half) values = math_ops.minimum( values, math_ops.cast(num_levels, self.dtype) - half) values = math_ops.cast(values, dtypes.int16) def loop_body(tensor): return coder_ops.range_encode( tensor, cdf, precision=self.range_coder_precision) strings = functional_ops.map_fn( loop_body, values, dtype=dtypes.string, back_prop=False) if not context.executing_eagerly(): strings.set_shape(inputs.shape[:1]) return strings
def testMap_MultiInputSingleOutput(self): nums = np.array([1, 2, 3, 4, 5, 6]) r = functional_ops.map_fn( lambda x: x[0] * x[1][0] + x[1][1], (nums, (nums, -nums)), dtype=dtypes.int64) self.assertEqual((6,), r.get_shape()) received = self.evaluate(r) self.assertAllEqual(nums * nums + (-nums), received)
def testWhileAndTensorArray(self): with self.cached_session() as sess: param = constant_op.constant(2.0) y0 = constant_op.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], name="elems") # map_fn uses TensorArray internally. r = functional_ops.map_fn(lambda x: math_ops.multiply(x, param), y0) self.assertAllClose([2.0, 4.0, 6.0, 8.0, 10.0, 12.0], self.evaluate(r)) r = gradients_impl.gradients(r, param)[0] self.assertAllClose(21.0, self.evaluate(r))
def build_dataset(row, num): # pylint: disable=g-long-lambda iterator = dataset_ops.make_initializable_iterator( dataset_ops.Dataset.from_tensors(row).map( lambda elems: functional_ops.map_fn( lambda x: control_map_fn(x, num), elems))) init_op = iterator.initializer get_next = iterator.get_next() return init_op, get_next
def loop(): random_seed.set_random_seed(0) x1 = random_ops.truncated_normal([1, 784], seed=0) x2 = random_ops.truncated_normal([1, 784], seed=0) x3 = random_ops.truncated_normal([1, 784], seed=0) x4 = random_ops.truncated_normal([1, 784], seed=0) elems = (x1, x2, x3, x4) outputs = functional_ops.map_fn(two_layer_model, elems, dtype=dtypes.float32) return outputs
def tensors_to_item(self, keys_to_tensors): """See base class.""" image_buffer = keys_to_tensors[self._image_key] image_format = keys_to_tensors[self._format_key] if self._repeated: return functional_ops.map_fn(lambda x: self._decode(x, image_format), image_buffer, dtype=self._dtype) else: return self._decode(image_buffer, image_format)
def _loop_with_vec_and_4d(): random_seed.set_random_seed(0) x1 = random_ops.truncated_normal([1, 784], seed=0) x2 = random_ops.truncated_normal([1, 784], seed=0) x3 = random_ops.truncated_normal([1, 784], seed=0) x4 = random_ops.truncated_normal([1, 784], seed=0) elems = (x1, x2, x3, x4) outputs = functional_ops.map_fn( _model_with_vec_and_4d, elems, dtype=dtypes.float32) return outputs
def testMap_Grad(self): with self.cached_session(): param = constant_op.constant(2.0) elems = constant_op.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], name="elems") y = functional_ops.map_fn( lambda x: math_ops.multiply(math_ops.square(x), param), elems) r = gradients_impl.gradients(y, param)[0] self.assertAllEqual(91.0, self.evaluate(r)) r = gradients_impl.gradients(y, elems)[0] self.assertAllEqual([4.0, 8.0, 12.0, 16.0, 20.0, 24.0], self.evaluate(r))
def input_fn(): starts = random_ops.random_uniform( [batch_size], maxval=(2 * np.pi), seed=seed) sin_curves = functional_ops.map_fn( _sin_fn, (starts,), dtype=dtypes.float32) inputs = array_ops.expand_dims( array_ops.slice(sin_curves, [0, 0], [batch_size, sequence_length]), 2) labels = array_ops.slice(sin_curves, [0, 1], [batch_size, sequence_length]) return {'inputs': inputs}, labels
def testMap_SingleInputMultiOutput(self): nums = np.array([1, 2, 3, 4, 5, 6]) r = functional_ops.map_fn( lambda x: ((x + 3) * 2, -(x + 3) * 2), nums, dtype=(dtypes.int64, dtypes.int64)) self.assertEqual(2, len(r)) self.assertEqual((6,), r[0].get_shape()) self.assertEqual((6,), r[1].get_shape()) received = self.evaluate(r) self.assertAllEqual((nums + 3) * 2, received[0]) self.assertAllEqual(-(nums + 3) * 2, received[1])
def testMap_MultiInputSameStructureOutput(self): nums = np.array([1, 2, 3, 4, 5, 6]) r = functional_ops.map_fn(lambda x: (x[1][0], (x[1][1], x[0])), (nums, (2 * nums, -nums))) r = [r[0], r[1][0], r[1][1]] self.assertEqual((6,), r[0].get_shape()) self.assertEqual((6,), r[1].get_shape()) self.assertEqual((6,), r[2].get_shape()) received = self.evaluate(r) self.assertAllEqual(2 * nums, received[0]) self.assertAllEqual(-nums, received[1]) self.assertAllEqual(nums, received[2])
def classifier_score(images, classifier_fn, num_batches=1): """Classifier score for evaluating a conditional generative model. This is based on the Inception Score, but for an arbitrary classifier. This technique is described in detail in https://arxiv.org/abs/1606.03498. In summary, this function calculates exp( E[ KL(p(y|x) || p(y)) ] ) which captures how different the network's classification prediction is from the prior distribution over classes. Args: images: Images to calculate the classifier score for. classifier_fn: A function that takes images and produces logits based on a classifier. num_batches: Number of batches to split `generated_images` in to in order to efficiently run them through the classifier network. Returns: The classifier score. A floating-point scalar. """ generated_images_list = array_ops.split( images, num_or_size_splits=num_batches) # Compute the classifier splits using the memory-efficient `map_fn`. logits = functional_ops.map_fn( fn=classifier_fn, elems=array_ops.stack(generated_images_list), parallel_iterations=1, back_prop=False, swap_memory=True, name='RunClassifier') logits = array_ops.concat(array_ops.unstack(logits), 0) logits.shape.assert_has_rank(2) # Use maximum precision for best results. logits_dtype = logits.dtype if logits_dtype != dtypes.float64: logits = math_ops.cast(logits, dtypes.float64) p = nn_ops.softmax(logits) q = math_ops.reduce_mean(p, axis=0) kl = _kl_divergence(p, logits, q) kl.shape.assert_has_rank(1) log_score = math_ops.reduce_mean(kl) final_score = math_ops.exp(log_score) if logits_dtype != dtypes.float64: final_score = math_ops.cast(final_score, dtypes.float64) return final_score
def testUseStepContainerInMap(self): row = np.arange(6) iterator = dataset_ops.make_initializable_iterator( dataset_ops.Dataset.from_tensors(row) .map(lambda elems: functional_ops.map_fn(lambda x: x * x, elems))) init_op = iterator.initializer get_next = iterator.get_next() with self.cached_session() as sess: sess.run(init_op) self.assertAllEqual(row**2, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next)
def map_fn(fn, labeled_tensor, name=None): """Map on the list of tensors unpacked from labeled_tensor. See tf.map_fn. Args: fn: The function to apply to each unpacked LabeledTensor. It should have type LabeledTensor -> LabeledTensor. labeled_tensor: The input tensor. name: Optional op name. Returns: A tensor that packs the results of applying fn to the list of tensors unpacked from labeled_tensor. """ with ops.name_scope(name, 'lt_map_fn', [labeled_tensor]) as scope: labeled_tensor = core.convert_to_labeled_tensor(labeled_tensor) unpack_lts = unpack(labeled_tensor) # TODO(ericmc): Fix this upstream. if labeled_tensor.dtype == dtypes.string: # We must construct the full graph here, because functional_ops.map_fn # doesn't work for string-valued tensors. # Constructing the full graph may be slow. map_lts = [fn(t) for t in unpack_lts] return pack(map_lts, list(labeled_tensor.axes.values())[0], name=scope) else: # Figure out what the axis labels should be, but use tf.map_fn to # construct the graph because it's efficient. # It may be slow to construct the full graph, so we infer the labels from # the first element. # TODO(ericmc): This builds a subgraph which then gets thrown away. # Find a more elegant solution. first_map_lt = fn(unpack_lts[0]) final_axes = list(labeled_tensor.axes.values())[:1] + list( first_map_lt.axes.values()) @tc.returns(ops.Tensor) @tc.accepts(ops.Tensor) def tf_fn(tensor): original_axes = list(labeled_tensor.axes.values())[1:] tensor_lt = core.LabeledTensor(tensor, original_axes) return fn(tensor_lt).tensor map_op = functional_ops.map_fn( tf_fn, labeled_tensor.tensor, dtype=first_map_lt.dtype) map_lt = core.LabeledTensor(map_op, final_axes) return core.identity(map_lt, name=scope)
def benchmark_map_fn(self): with ops.Graph().as_default(): b = 256 params = 1000 inp = random_ops.random_normal((b, params)) map_fn = lambda x: x * x def pfor_map_fn(f, x): return pfor_control_flow_ops.pfor( lambda i: f(array_ops.gather(x, i)), array_ops.shape(x)[0]) map_output = functional_ops.map_fn(map_fn, inp) pfor_output = pfor_map_fn(map_fn, inp) self._run(map_output, 100, name="tf_map_fn") self._run(pfor_output, 100, name="pfor_map_fn")
def testCaseAndCondInWhileInMap(self): def control_map_fn(x, y): def multiply(): return x * 2 def divide(): return x // 2 def defaults_two(): return control_flow_ops.cond( math_ops.equal(math_ops.mod(x, 2), 0), multiply, divide, name="cond_mult") pred_fn_pairs = { math_ops.logical_or(math_ops.equal(y, 2), math_ops.equal(y, 3)): defaults_two, } return control_flow_ops.case( pred_fn_pairs, default=multiply, exclusive=True) row = np.arange(6) num = 2 # pylint: disable=g-long-lambda iterator = ( dataset_ops.Dataset.from_tensors(row).map( lambda elems: functional_ops.map_fn(lambda x: control_map_fn(x, num), elems) ).make_initializable_iterator()) # pylint: enable=g-long-lambda init_op = iterator.initializer get_next = iterator.get_next() with self.cached_session() as sess: sess.run(init_op) self.assertAllEqual([(x // 2 if x % 2 else x * 2) if (num == 2 or num == 3) else x * 2 for x in row], sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next)
def classifier_score(images, classifier_fn, num_batches=1): """Classifier score for evaluating a conditional generative model. This is based on the Inception Score, but for an arbitrary classifier. This technique is described in detail in https://arxiv.org/abs/1606.03498. In summary, this function calculates exp( E[ KL(p(y|x) || p(y)) ] ) which captures how different the network's classification prediction is from the prior distribution over classes. NOTE: This function consumes images, computes their logits, and then computes the classifier score. If you would like to precompute many logits for large batches, use clasifier_score_from_logits(), which this method also uses. Args: images: Images to calculate the classifier score for. classifier_fn: A function that takes images and produces logits based on a classifier. num_batches: Number of batches to split `generated_images` in to in order to efficiently run them through the classifier network. Returns: The classifier score. A floating-point scalar of the same type as the output of `classifier_fn`. """ generated_images_list = array_ops.split( images, num_or_size_splits=num_batches) # Compute the classifier splits using the memory-efficient `map_fn`. logits = functional_ops.map_fn( fn=classifier_fn, elems=array_ops.stack(generated_images_list), parallel_iterations=1, back_prop=False, swap_memory=True, name='RunClassifier') logits = array_ops.concat(array_ops.unstack(logits), 0) return classifier_score_from_logits(logits)
def benchmarkDefunVsMapFn(self): """Benchmarks to compare the performance of MapDefun vs tf.map_fn.""" @function.defun(input_signature=[tensor_spec.TensorSpec([], dtypes.int32)]) def defun(x): return array_ops.identity(x) def map_fn(x): return array_ops.identity(x) base = math_ops.range(100) for input_size in [10, 100, 1000, 10000]: num_iters = 100000 // input_size map_defun_op = map_defun.map_defun(defun, [base], [dtypes.int32], [()]) map_fn_op = functional_ops.map_fn(map_fn, base) self._run( map_defun_op, "benchmarkMapDefun_size_%d" % input_size, num_iters=num_iters) self._run( map_fn_op, "benchmarkMapFn_size_%d" % input_size, num_iters=num_iters)
def norm(tensor, ord='euclidean', axis=None, keepdims=None, name=None, keep_dims=None): r"""Computes the norm of vectors, matrices, and tensors. This function can compute several different vector norms (the 1-norm, the Euclidean or 2-norm, the inf-norm, and in general the p-norm for p > 0) and matrix norms (Frobenius, 1-norm, 2-norm and inf-norm). Args: tensor: `Tensor` of types `float32`, `float64`, `complex64`, `complex128` ord: Order of the norm. Supported values are 'fro', 'euclidean', `1`, `2`, `np.inf` and any positive real number yielding the corresponding p-norm. Default is 'euclidean' which is equivalent to Frobenius norm if `tensor` is a matrix and equivalent to 2-norm for vectors. Some restrictions apply: a) The Frobenius norm `fro` is not defined for vectors, b) If axis is a 2-tuple (matrix norm), only 'euclidean', 'fro', `1`, `2`, `np.inf` are supported. See the description of `axis` on how to compute norms for a batch of vectors or matrices stored in a tensor. axis: If `axis` is `None` (the default), the input is considered a vector and a single vector norm is computed over the entire set of values in the tensor, i.e. `norm(tensor, ord=ord)` is equivalent to `norm(reshape(tensor, [-1]), ord=ord)`. If `axis` is a Python integer, the input is considered a batch of vectors, and `axis` determines the axis in `tensor` over which to compute vector norms. If `axis` is a 2-tuple of Python integers it is considered a batch of matrices and `axis` determines the axes in `tensor` over which to compute a matrix norm. Negative indices are supported. Example: If you are passing a tensor that can be either a matrix or a batch of matrices at runtime, pass `axis=[-2,-1]` instead of `axis=None` to make sure that matrix norms are computed. keepdims: If True, the axis indicated in `axis` are kept with size 1. Otherwise, the dimensions in `axis` are removed from the output shape. name: The name of the op. keep_dims: Deprecated alias for `keepdims`. Returns: output: A `Tensor` of the same type as tensor, containing the vector or matrix norms. If `keepdims` is True then the rank of output is equal to the rank of `tensor`. Otherwise, if `axis` is none the output is a scalar, if `axis` is an integer, the rank of `output` is one less than the rank of `tensor`, if `axis` is a 2-tuple the rank of `output` is two less than the rank of `tensor`. Raises: ValueError: If `ord` or `axis` is invalid. @compatibility(numpy) Mostly equivalent to numpy.linalg.norm. Not supported: ord <= 0, 2-norm for matrices, nuclear norm. Other differences: a) If axis is `None`, treats the flattened `tensor` as a vector regardless of rank. b) Explicitly supports 'euclidean' norm as the default, including for higher order tensors. @end_compatibility """ keepdims = deprecation.deprecated_argument_lookup('keepdims', keepdims, 'keep_dims', keep_dims) if keepdims is None: keepdims = False is_matrix_norm = ((isinstance(axis, tuple) or isinstance(axis, list)) and len(axis) == 2) if is_matrix_norm: axis = tuple(axis) if (not isinstance(axis[0], int) or not isinstance(axis[1], int) or axis[0] == axis[1]): raise ValueError( "'axis' must be None, an integer, or a tuple of 2 unique integers" ) supported_matrix_norms = ['euclidean', 'fro', 1, 2, np.inf] if ord not in supported_matrix_norms: raise ValueError( "'ord' must be a supported matrix norm in %s, got %s" % (supported_matrix_norms, ord)) else: if not (isinstance(axis, int) or axis is None): raise ValueError( "'axis' must be None, an integer, or a tuple of 2 unique integers" ) supported_vector_norms = ['euclidean', 1, 2, np.inf] if (not np.isreal(ord) or ord <= 0) and ord not in supported_vector_norms: raise ValueError("'ord' must be a supported vector norm, got %s" % ord) if axis is not None: axis = (axis, ) with ops.name_scope(name, 'norm', [tensor]): tensor = ops.convert_to_tensor(tensor) if ord in ['fro', 'euclidean', 2, 2.0]: if is_matrix_norm and ord in [2, 2.0]: rank = array_ops.rank(tensor) positive_axis = functional_ops.map_fn( lambda i: control_flow_ops.cond(i >= 0, lambda: i, lambda: i + rank), ops.convert_to_tensor(axis)) axes = math_ops.range(rank) perm_before = array_ops.concat([ array_ops.setdiff1d(axes, positive_axis)[0], positive_axis ], axis=0) perm_after = functional_ops.map_fn( lambda i: math_ops.cast(array_ops.squeeze( array_ops.where(math_ops.equal(perm_before, i))), dtype=dtypes.int32), axes) permed = array_ops.transpose(tensor, perm=perm_before) matrix_2_norm = array_ops.expand_dims(math_ops.reduce_max( math_ops.abs( gen_linalg_ops.svd(permed, compute_uv=False)[0]), axis=-1, keepdims=True), axis=-1) result = array_ops.transpose(matrix_2_norm, perm=perm_after) else: result = math_ops.sqrt( math_ops.reduce_sum(tensor * math_ops.conj(tensor), axis, keepdims=True)) else: result = math_ops.abs(tensor) if ord == 1: sum_axis = None if axis is None else axis[0] result = math_ops.reduce_sum(result, sum_axis, keepdims=True) if is_matrix_norm: result = math_ops.reduce_max(result, axis[-1], keepdims=True) elif ord == np.inf: if is_matrix_norm: result = math_ops.reduce_sum(result, axis[1], keepdims=True) max_axis = None if axis is None else axis[0] result = math_ops.reduce_max(result, max_axis, keepdims=True) else: # General p-norms (positive p only) result = math_ops.pow( math_ops.reduce_sum(math_ops.pow(result, ord), axis, keepdims=True), 1.0 / ord) if not keepdims: result = array_ops.squeeze(result, axis) return result
def kernel_classifier_distance_and_std_from_activations( real_activations, generated_activations, max_block_size=1024, dtype=None): # pylint: disable=no-member """Kernel "classifier" distance for evaluating a generative model. This methods computes the kernel classifier distance from activations of real images and generated images. This can be used independently of the kernel_classifier_distance() method, especially in the case of using large batches during evaluation where we would like to precompute all of the activations before computing the classifier distance, or if we want to compute multiple metrics based on the same images. It also returns a rough estimate of the standard error of the estimator. This technique is described in detail in https://arxiv.org/abs/1801.01401. Given two distributions P and Q of activations, this function calculates E_{X, X' ~ P}[k(X, X')] + E_{Y, Y' ~ Q}[k(Y, Y')] - 2 E_{X ~ P, Y ~ Q}[k(X, Y)] where k is the polynomial kernel k(x, y) = ( x^T y / dimension + 1 )^3. This captures how different the distributions of real and generated images' visual features are. Like the Frechet distance (and unlike the Inception score), this is a true distance and incorporates information about the target images. Unlike the Frechet score, this function computes an *unbiased* and asymptotically normal estimator, which makes comparing estimates across models much more intuitive. The estimator used takes time quadratic in max_block_size. Larger values of max_block_size will decrease the variance of the estimator but increase the computational cost. This differs slightly from the estimator used by the original paper; it is the block estimator of https://arxiv.org/abs/1307.1954. The estimate of the standard error will also be more reliable when there are more blocks, i.e. when max_block_size is smaller. NOTE: the blocking code assumes that real_activations and generated_activations are both in random order. If either is sorted in a meaningful order, the estimator will behave poorly. Args: real_activations: 2D Tensor containing activations of real data. Shape is [batch_size, activation_size]. generated_activations: 2D Tensor containing activations of generated data. Shape is [batch_size, activation_size]. max_block_size: integer, default 1024. The distance estimator splits samples into blocks for computational efficiency. Larger values are more computationally expensive but decrease the variance of the distance estimate. Having a smaller block size also gives a better estimate of the standard error. dtype: if not None, coerce activations to this dtype before computations. Returns: The Kernel Inception Distance. A floating-point scalar of the same type as the output of the activations. An estimate of the standard error of the distance estimator (a scalar of the same type). """ real_activations.shape.assert_has_rank(2) generated_activations.shape.assert_has_rank(2) real_activations.shape[1].assert_is_compatible_with( generated_activations.shape[1]) if dtype is None: dtype = real_activations.dtype assert generated_activations.dtype == dtype else: real_activations = math_ops.cast(real_activations, dtype) generated_activations = math_ops.cast(generated_activations, dtype) # Figure out how to split the activations into blocks of approximately # equal size, with none larger than max_block_size. n_r = array_ops.shape(real_activations)[0] n_g = array_ops.shape(generated_activations)[0] n_bigger = math_ops.maximum(n_r, n_g) n_blocks = math_ops.to_int32(math_ops.ceil(n_bigger / max_block_size)) v_r = n_r // n_blocks v_g = n_g // n_blocks n_plusone_r = n_r - v_r * n_blocks n_plusone_g = n_g - v_g * n_blocks sizes_r = array_ops.concat([ array_ops.fill([n_blocks - n_plusone_r], v_r), array_ops.fill([n_plusone_r], v_r + 1), ], 0) sizes_g = array_ops.concat([ array_ops.fill([n_blocks - n_plusone_g], v_g), array_ops.fill([n_plusone_g], v_g + 1), ], 0) zero = array_ops.zeros([1], dtype=dtypes.int32) inds_r = array_ops.concat([zero, math_ops.cumsum(sizes_r)], 0) inds_g = array_ops.concat([zero, math_ops.cumsum(sizes_g)], 0) dim = math_ops.cast(real_activations.shape[1], dtype) def compute_kid_block(i): 'Compute the ith block of the KID estimate.' r_s = inds_r[i] r_e = inds_r[i + 1] r = real_activations[r_s:r_e] m = math_ops.cast(r_e - r_s, dtype) g_s = inds_g[i] g_e = inds_g[i + 1] g = generated_activations[g_s:g_e] n = math_ops.cast(g_e - g_s, dtype) k_rr = (math_ops.matmul(r, r, transpose_b=True) / dim + 1)**3 k_rg = (math_ops.matmul(r, g, transpose_b=True) / dim + 1)**3 k_gg = (math_ops.matmul(g, g, transpose_b=True) / dim + 1)**3 return (-2 * math_ops.reduce_mean(k_rg) + (math_ops.reduce_sum(k_rr) - math_ops.trace(k_rr)) / (m * (m - 1)) + (math_ops.reduce_sum(k_gg) - math_ops.trace(k_gg)) / (n * (n - 1))) ests = functional_ops.map_fn(compute_kid_block, math_ops.range(n_blocks), dtype=dtype, back_prop=False) mn = math_ops.reduce_mean(ests) # nn_impl.moments doesn't use the Bessel correction, which we want here n_blocks_ = math_ops.cast(n_blocks, dtype) var = control_flow_ops.cond( math_ops.less_equal(n_blocks, 1), lambda: array_ops.constant(float('nan'), dtype=dtype), lambda: math_ops.reduce_sum(math_ops.square(ests - mn)) / (n_blocks_ - 1)) return mn, math_ops.sqrt(var / n_blocks_)
def testUseStepContainerInMap(self): row = np.arange(6) dataset = dataset_ops.Dataset.from_tensors(row).map( lambda elems: functional_ops.map_fn(lambda x: x * x, elems)) self.assertDatasetProduces(dataset, expected_output=[row**2])
def frechet_classifier_distance(real_images, generated_images, classifier_fn, num_batches=1): """Classifier distance for evaluating a conditional generative model. This is based on the Frechet Inception distance, but for an arbitrary classifier. This technique is described in detail in https://arxiv.org/abs/1706.08500. Given two Gaussian distribution with means m and m_w and covariance matrices C and C_w, this function calcuates |m - m_w|^2 + Tr(C + C_w - 2(C * C_w)^(1/2)) which captures how different the distributions of real images and generated images (or more accurately, their visual features) are. Note that unlike the Inception score, this is a true distance and utilizes information about real world images. Args: real_images: Real images to use to compute Frechet Inception distance. generated_images: Generated images to use to compute Frechet Inception distance. classifier_fn: A function that takes images and produces activations based on a classifier. num_batches: Number of batches to split images in to in order to efficiently run them through the classifier network. Returns: The Frechet Inception distance. A floating-point scalar. """ real_images_list = array_ops.split(real_images, num_or_size_splits=num_batches) generated_images_list = array_ops.split(generated_images, num_or_size_splits=num_batches) imgs = array_ops.stack(real_images_list + generated_images_list) # Compute the activations using the memory-efficient `map_fn`. activations = functional_ops.map_fn(fn=classifier_fn, elems=imgs, parallel_iterations=1, back_prop=False, swap_memory=True, name='RunClassifier') # Split the activations by the real and generated images. real_a, gen_a = array_ops.split(activations, [num_batches, num_batches], 0) # Ensure the activations have the right shapes. real_a = array_ops.concat(array_ops.unstack(real_a), 0) gen_a = array_ops.concat(array_ops.unstack(gen_a), 0) real_a.shape.assert_has_rank(2) gen_a.shape.assert_has_rank(2) # Compute mean and covariance matrices of activations. m = math_ops.reduce_mean(real_a, 0) m_v = math_ops.reduce_mean(gen_a, 0) dim = math_ops.to_float(array_ops.shape(m)[0]) sigma = math_ops.matmul(real_a - m, real_a - m, transpose_b=True) / dim sigma_v = math_ops.matmul(gen_a - m, gen_a - m, transpose_b=True) / dim # Take matrix square root of the product of covariance matrices. sqcc = _matrix_square_root(math_ops.matmul(sigma, sigma_v)) # Compute the two components of FID. trace = math_ops.trace(sigma + sigma_v - 2.0 * sqcc) mean = math_ops.square(linalg_ops.norm(m - m_v)) # This uses the L2 norm. fid = trace + mean return fid
def _predicate(xs): squared_xs = functional_ops.map_fn(lambda x: x * x, xs) summed = math_ops.reduce_sum(squared_xs) return math_ops.equal(summed, 1 + 4 + 9)
def testMapEmptyScalar(self): map_return = functional_ops.map_fn(lambda x: 1, constant_op.constant([])) self.assertAllEqual([0], map_return.get_shape().dims) self.assertAllEqual([0], self.evaluate(map_return).shape)
def testMapShape(self): x = constant_op.constant([[1, 2, 3], [4, 5, 6]]) y = functional_ops.map_fn(lambda e: e, x) self.assertAllEqual(y.get_shape(), self.evaluate(y).shape)
def compress(self, inputs): """Compress inputs and store their binary representations into strings. Args: inputs: `Tensor` with values to be compressed. Returns: String `Tensor` vector containing the compressed representation of each batch element of `inputs`. """ with ops.name_scope(self._name_scope()): inputs = ops.convert_to_tensor(inputs) if not self.built: # Check input assumptions set before layer building, e.g. input rank. input_spec.assert_input_compatibility(self.input_spec, inputs, self.name) if self.dtype is None: self._dtype = inputs.dtype.base_dtype.name self.build(inputs.shape) # Check input assumptions set after layer building, e.g. input shape. if not context.executing_eagerly(): input_spec.assert_input_compatibility(self.input_spec, inputs, self.name) ndim = self.input_spec.ndim channel_axis = self._channel_axis(ndim) # Tuple of slices for expanding dimensions of tensors below. slices = ndim * [None] + [slice(None)] slices[channel_axis] = slice(None) slices = tuple(slices) # Expand dimensions of CDF to input dimensions, keeping the channels along # the right dimension. cdf = self._quantized_cdf[slices[1:]] num_levels = array_ops.shape(cdf)[-1] - 1 # Bring inputs to the right range by centering the range on the medians. half = constant_op.constant(.5, dtype=self.dtype) medians = array_ops.squeeze(self._medians, [1, 2]) offsets = (math_ops.cast(num_levels // 2, self.dtype) + half) - medians # Expand offsets to input dimensions and add to inputs. values = inputs + offsets[slices[:-1]] # Clip to range and cast to integers. Because we have added .5 above, and # all values are positive, the cast effectively implements rounding. values = math_ops.maximum(values, half) values = math_ops.minimum( values, math_ops.cast(num_levels, self.dtype) - half) values = math_ops.cast(values, dtypes.int16) def loop_body(tensor): return coder_ops.range_encode( tensor, cdf, precision=self.range_coder_precision) strings = functional_ops.map_fn(loop_body, values, dtype=dtypes.string, back_prop=False) if not context.executing_eagerly(): strings.set_shape(inputs.shape[:1]) return strings
def testMapEmptyTensor(self): with self.test_session(): map_return = functional_ops.map_fn( lambda x: array_ops.zeros([3, 2]), constant_op.constant([])) self.assertAllEqual([0, 3, 2], map_return.get_shape().dims) self.assertAllEqual([0, 3, 2], map_return.eval().shape)
]) # FID TEST def resize_and_classify(x): INCEPTION_FINAL_POOL = 'pool_3:0' x = tf.image.resize_bilinear(x, [299, 299]) return tf.contrib.gan.eval.run_inception(x, output_tensor=INCEPTION_FINAL_POOL) fid_real_final = x_50k fid_z_final = tf.constant(np.random.randn(50000, 128), dtype='float32') fid_z_final_list = array_ops.split(fid_z_final, num_or_size_splits=50000 // 100) fid_z_final_batches = array_ops.stack(fid_z_final_list) fid_gen_final = functional_ops.map_fn( fn=partial(generator, reuse=True), elems=fid_z_final_batches, parallel_iterations=1, back_prop=False, swap_memory=True, name='RunGenerator' ) fid_gen_final = array_ops.concat(array_ops.unstack(fid_gen_final), 0) fid_final = tf.contrib.gan.eval.frechet_classifier_distance( fid_real_final, fid_gen_final, classifier_fn=resize_and_classify, num_batches=50000 // 100 ) fid_summary_final = tf.summary.merge([ tf.summary.scalar('fid_final', fid_final) ])
def add_stargan_image_summaries(stargan_model, num_images=2, display_diffs=False): """Adds image summaries to see StarGAN image results. If display_diffs is True, each image result has `2` rows and `num_domains + 1` columns. The first row looks like: [original_image, transformed_to_domain_0, transformed_to_domain_1, ...] The second row looks like: [no_modification_baseline, transformed_to_domain_0-original_image, ...] If display_diffs is False, only the first row is shown. IMPORTANT: Since the model originally does not transformed the image to every domains, we will transform them on-the-fly within this function in parallel. Args: stargan_model: A StarGANModel tuple. num_images: The number of examples/images to be transformed and shown. display_diffs: Also display the difference between generated and target. Raises: ValueError: If input_data is not images. ValueError: If input_data_domain_label is not rank 2. ValueError: If dimension 2 of input_data_domain_label is not fully defined. """ _assert_is_image(stargan_model.input_data) stargan_model.input_data_domain_label.shape.assert_has_rank(2) stargan_model.input_data_domain_label.shape[1:].assert_is_fully_defined() num_domains = stargan_model.input_data_domain_label.get_shape().as_list( )[-1] def _build_image(image): """Helper function to create a result for each image on the fly.""" # Expand the first dimension as batch_size = 1. images = array_ops.expand_dims(image, axis=0) # Tile the image num_domains times, so we can get all transformed together. images = array_ops.tile(images, [num_domains, 1, 1, 1]) # Create the targets to 0, 1, 2, ..., num_domains-1. targets = array_ops.one_hot(list(range(num_domains)), num_domains) with variable_scope.variable_scope(stargan_model.generator_scope, reuse=True): # Add the original image. output_images_list = [image] # Generate the image and add to the list. gen_images = stargan_model.generator_fn(images, targets) gen_images_list = array_ops.split(gen_images, num_domains) gen_images_list = [ array_ops.squeeze(img, axis=0) for img in gen_images_list ] output_images_list.extend(gen_images_list) # Display diffs. if display_diffs: diff_images = gen_images - images diff_images_list = array_ops.split(diff_images, num_domains) diff_images_list = [ array_ops.squeeze(img, axis=0) for img in diff_images_list ] output_images_list.append(array_ops.zeros_like(image)) output_images_list.extend(diff_images_list) # Create the final image. final_image = eval_utils.image_reshaper(output_images_list, num_cols=num_domains + 1) # Reduce the first rank. return array_ops.squeeze(final_image, axis=0) summary.image('stargan_image_generation', functional_ops.map_fn(_build_image, stargan_model.input_data[:num_images], parallel_iterations=num_images, back_prop=False, swap_memory=True), max_outputs=num_images)
def testMapOverScalarErrors(self): with self.assertRaisesRegexp(ValueError, "not scalars"): functional_ops.map_fn(lambda x: x, [1, 2]) with self.assertRaisesRegexp(ValueError, "not a scalar"): functional_ops.map_fn(lambda x: x, 1)
def frechet_classifier_distance(real_images, generated_images, classifier_fn, num_batches=1): """Classifier distance for evaluating a generative model. This is based on the Frechet Inception distance, but for an arbitrary classifier. This technique is described in detail in https://arxiv.org/abs/1706.08500. Given two Gaussian distribution with means m and m_w and covariance matrices C and C_w, this function calculates |m - m_w|^2 + Tr(C + C_w - 2(C * C_w)^(1/2)) which captures how different the distributions of real images and generated images (or more accurately, their visual features) are. Note that unlike the Inception score, this is a true distance and utilizes information about real world images. Note that when computed using sample means and sample covariance matrices, Frechet distance is biased. It is more biased for small sample sizes. (e.g. even if the two distributions are the same, for a small sample size, the expected Frechet distance is large). It is important to use the same sample size to compute Frechet classifier distance when comparing two generative models. NOTE: This function consumes images, computes their activations, and then computes the classifier score. If you would like to precompute many activations for real and generated images for large batches, please use frechet_clasifier_distance_from_activations(), which this method also uses. Args: real_images: Real images to use to compute Frechet Inception distance. generated_images: Generated images to use to compute Frechet Inception distance. classifier_fn: A function that takes images and produces activations based on a classifier. num_batches: Number of batches to split images in to in order to efficiently run them through the classifier network. Returns: The Frechet Inception distance. A floating-point scalar of the same type as the output of `classifier_fn`. """ real_images_list = array_ops.split(real_images, num_or_size_splits=num_batches) generated_images_list = array_ops.split(generated_images, num_or_size_splits=num_batches) imgs = array_ops.stack(real_images_list + generated_images_list) # Compute the activations using the memory-efficient `map_fn`. activations = functional_ops.map_fn(fn=classifier_fn, elems=imgs, parallel_iterations=1, back_prop=False, swap_memory=True, name='RunClassifier') # Split the activations by the real and generated images. real_a, gen_a = array_ops.split(activations, [num_batches, num_batches], 0) # Ensure the activations have the right shapes. real_a = array_ops.concat(array_ops.unstack(real_a), 0) gen_a = array_ops.concat(array_ops.unstack(gen_a), 0) return frechet_classifier_distance_from_activations(real_a, gen_a)
def build_dataset(row, num): # pylint: disable=g-long-lambda dataset = dataset_ops.Dataset.from_tensors(row).map( lambda elems: functional_ops.map_fn( lambda x: control_map_fn(x, num), elems)) return self.getNext(dataset)
def frechet_classifier_distance(real_images, generated_images, classifier_fn, num_batches=1): """Classifier distance for evaluating a generative model. This is based on the Frechet Inception distance, but for an arbitrary classifier. This technique is described in detail in https://arxiv.org/abs/1706.08500. Given two Gaussian distribution with means m and m_w and covariance matrices C and C_w, this function calcuates |m - m_w|^2 + Tr(C + C_w - 2(C * C_w)^(1/2)) which captures how different the distributions of real images and generated images (or more accurately, their visual features) are. Note that unlike the Inception score, this is a true distance and utilizes information about real world images. Note that when computed using sample means and sample covariance matrices, Frechet distance is biased. It is more biased for small sample sizes. (e.g. even if the two distributions are the same, for a small sample size, the expected Frechet distance is large). It is important to use the same sample size to compute frechet classifier distance when comparing two generative models. Args: real_images: Real images to use to compute Frechet Inception distance. generated_images: Generated images to use to compute Frechet Inception distance. classifier_fn: A function that takes images and produces activations based on a classifier. num_batches: Number of batches to split images in to in order to efficiently run them through the classifier network. Returns: The Frechet Inception distance. A floating-point scalar. """ real_images_list = array_ops.split( real_images, num_or_size_splits=num_batches) generated_images_list = array_ops.split( generated_images, num_or_size_splits=num_batches) imgs = array_ops.stack(real_images_list + generated_images_list) # Compute the activations using the memory-efficient `map_fn`. activations = functional_ops.map_fn( fn=classifier_fn, elems=imgs, parallel_iterations=1, back_prop=False, swap_memory=True, name='RunClassifier') # Split the activations by the real and generated images. real_a, gen_a = array_ops.split(activations, [num_batches, num_batches], 0) # Ensure the activations have the right shapes. real_a = array_ops.concat(array_ops.unstack(real_a), 0) gen_a = array_ops.concat(array_ops.unstack(gen_a), 0) real_a.shape.assert_has_rank(2) gen_a.shape.assert_has_rank(2) # Compute mean and covariance matrices of activations. m = math_ops.reduce_mean(real_a, 0) m_v = math_ops.reduce_mean(gen_a, 0) num_examples = math_ops.to_float(array_ops.shape(real_a)[0]) # sigma = (1 / (n - 1)) * (X - mu) (X - mu)^T sigma = math_ops.matmul( real_a - m, real_a - m, transpose_a=True) / (num_examples - 1) sigma_v = math_ops.matmul( gen_a - m_v, gen_a - m_v, transpose_a=True) / (num_examples - 1) # Find the Tr(sqrt(sigma sigma_v)) component of FID sqrt_trace_component = trace_sqrt_product(sigma, sigma_v) # Compute the two components of FID. # First the covariance component. # Here, note that trace(A + B) = trace(A) + trace(B) trace = math_ops.trace(sigma + sigma_v) - 2.0 * sqrt_trace_component # Next the distance between means. mean = math_ops.square(linalg_ops.norm(m - m_v)) # This uses the L2 norm. fid = trace + mean return fid
def decompress(self, strings, shape, channels=None): """Decompress values from their compressed string representations. Args: strings: A string `Tensor` vector containing the compressed data. shape: A `Tensor` vector of int32 type. Contains the shape of the tensor to be decompressed, excluding the batch dimension. channels: Integer. Specifies the number of channels statically. Needs only be set if the layer hasn't been built yet (i.e., this is the first input it receives). Returns: The decompressed `Tensor`. Its shape will be equal to `shape` prepended with the batch dimension from `strings`. Raises: ValueError: If the length of `shape` isn't available at graph construction time. """ with ops.name_scope(self._name_scope()): strings = ops.convert_to_tensor(strings) shape = ops.convert_to_tensor(shape) if self.built: ndim = self.input_spec.ndim channel_axis = self._channel_axis(ndim) if channels is None: channels = self.input_spec.axes[channel_axis] else: if not (shape.shape.is_fully_defined() and shape.shape.ndims == 1): raise ValueError("`shape` must be a vector with known length.") ndim = shape.shape[0].value + 1 channel_axis = self._channel_axis(ndim) input_shape = ndim * [None] input_shape[channel_axis] = channels self.build(input_shape) # Tuple of slices for expanding dimensions of tensors below. slices = ndim * [None] + [slice(None)] slices[channel_axis] = slice(None) slices = tuple(slices) # Expand dimensions of CDF to input dimensions, keeping the channels along # the right dimension. cdf = self._quantized_cdf[slices[1:]] num_levels = array_ops.shape(cdf)[-1] - 1 def loop_body(string): return coder_ops.range_decode( string, shape, cdf, precision=self.range_coder_precision) outputs = functional_ops.map_fn( loop_body, strings, dtype=dtypes.int16, back_prop=False) outputs = math_ops.cast(outputs, self.dtype) medians = array_ops.squeeze(self._medians, [1, 2]) offsets = math_ops.cast(num_levels // 2, self.dtype) - medians outputs -= offsets[slices[:-1]] if not context.executing_eagerly(): outputs_shape = ndim * [None] outputs_shape[0] = strings.shape[0] outputs_shape[channel_axis] = channels outputs.set_shape(outputs_shape) return outputs
def testMapShape(self): with self.test_session(): x = constant_op.constant([[1, 2, 3], [4, 5, 6]]) y = functional_ops.map_fn(lambda e: e, x) self.assertAllEqual(y.get_shape(), y.eval().shape)
def testMapEmptyTensor(self): with self.cached_session(): map_return = functional_ops.map_fn(lambda x: array_ops.zeros([3, 2]), constant_op.constant([])) self.assertAllEqual([0, 3, 2], map_return.get_shape().dims) self.assertAllEqual([0, 3, 2], self.evaluate(map_return).shape)
def testMap_SimpleNotTensor(self): nums = np.array([1, 2, 3, 4, 5, 6]) r = functional_ops.map_fn( lambda x: math_ops.multiply(math_ops.add(x, 3), 2), nums) self.assertAllEqual( np.array([(x + 3) * 2 for x in nums]), self.evaluate(r))
def testMapUnknownShape(self): x = array_ops.placeholder(dtypes.float32) y = functional_ops.map_fn(lambda e: e, x) self.assertIs(None, y.get_shape().dims)
tfgan.eval.run_inception(images, output_tensor=['logits:0', 'pool_3:0'])) input_images_ = tf.placeholder(tf.float32, [None, 3, None, None]) images_ = tf.transpose(input_images_, [0, 2, 3, 1]) size_ = 299 images_ = tf.image.resize_bilinear(images_, [size_, size_]) generated_images_list_ = array_ops.split(images_, num_or_size_splits=1) with tf.device('/gpu:0'): # Run images through Inception. logits_, activations_ = functional_ops.map_fn( fn=_run_inception, elems=array_ops.stack(generated_images_list_), parallel_iterations=1, back_prop=False, dtype=(tf.float32, tf.float32), swap_memory=True, name='RunClassifier') logits_ = array_ops.concat(array_ops.unstack(logits_), 0) activations_ = array_ops.concat(array_ops.unstack(activations_), 0) activations1_ = tf.placeholder(tf.float32, [None, None], name='activations1') activations2_ = tf.placeholder(tf.float32, [None, None], name='activations2') fcd = tfgan.eval.frechet_classifier_distance_from_activations( activations1_, activations2_) def activations_to_distance(activations1, activations2): print('Compute distance')
def testMapEmptyScalar(self): with self.test_session(): map_return = functional_ops.map_fn(lambda x: 1, constant_op.constant([])) self.assertAllEqual([0], map_return.get_shape().dims) self.assertAllEqual([0], map_return.eval().shape)
def generate_one(d): fn = lambda _: random_ops.random_shuffle(math_ops.range(d), seed=seed) return functional_ops.map_fn(fn, sample_range)