def testAddWeight(self): layer = base_layers.Layer(name='my_layer') # Test basic variable creation. variable = layer.add_variable( 'my_var', [2, 2], initializer=init_ops.zeros_initializer()) self.assertEqual(variable.name, 'my_layer/my_var:0') self.assertListEqual(layer.variables, [variable]) self.assertListEqual(layer.trainable_variables, [variable]) self.assertListEqual(layer.non_trainable_variables, []) if context.in_graph_mode(): self.assertListEqual( layer.variables, ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES)) # Test non-trainable variable creation. # layer.add_variable should work even outside `build` and `call`. variable_2 = layer.add_variable( 'non_trainable_var', [2, 2], initializer=init_ops.zeros_initializer(), trainable=False) self.assertListEqual(layer.variables, [variable, variable_2]) self.assertListEqual(layer.trainable_variables, [variable]) self.assertListEqual(layer.non_trainable_variables, [variable_2]) if context.in_graph_mode(): self.assertEqual( len(ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES)), 1) # regularizers only supported in GRAPH mode. regularizer = lambda x: math_ops.reduce_sum(x) * 1e-3 variable = layer.add_variable( 'reg_var', [2, 2], initializer=init_ops.zeros_initializer(), regularizer=regularizer) self.assertEqual(len(layer.losses), 1)
def testAddVariable(self): obj = NonLayerCheckpointable() with self.assertRaisesRegexp(ValueError, "do not specify shape"): checkpointable_utils.add_variable( obj, name="shape_specified_twice", shape=[], initializer=1) constant_initializer = checkpointable_utils.add_variable( obj, name="constant_initializer", initializer=1) with variable_scope.variable_scope("some_variable_scope"): ones_initializer = checkpointable_utils.add_variable( obj, name="ones_initializer", shape=[2], initializer=init_ops.ones_initializer(dtype=dtypes.float32)) bare_initializer = checkpointable_utils.add_variable( obj, name="bare_initializer", shape=[2, 2], dtype=dtypes.float64, initializer=init_ops.zeros_initializer) # Even in graph mode, there are no naming conflicts between objects, only # naming conflicts within an object. other_duplicate = resource_variable_ops.ResourceVariable( name="duplicate", initial_value=1.) duplicate = checkpointable_utils.add_variable( obj, name="duplicate", shape=[]) with self.assertRaisesRegexp(ValueError, "'duplicate' already exists"): checkpointable_utils.add_variable(obj, name="duplicate", shape=[]) if context.in_graph_mode(): self.evaluate(variables.global_variables_initializer()) self.assertEqual("constant_initializer:0", constant_initializer.name) self.assertEqual(1, self.evaluate(constant_initializer)) self.assertEqual("some_variable_scope/ones_initializer:0", ones_initializer.name) self.assertAllEqual([1, 1], self.evaluate(ones_initializer)) self.assertAllEqual([[0., 0.], [0., 0.]], self.evaluate(bare_initializer)) self.assertEqual("a_variable:0", obj.a_variable.name) self.assertEqual("duplicate:0", other_duplicate.name) if context.in_graph_mode(): # The .name attribute may be globally influenced, but the checkpoint name # won't be (tested below). self.assertEqual("duplicate_1:0", duplicate.name) else: # When executing eagerly, there's no uniquification of variable names. The # checkpoint name will be the same. self.assertEqual("duplicate:0", duplicate.name) named_variables, _ = checkpointable_utils._serialize_object_graph(obj) expected_checkpoint_names = ( "a_variable/.ATTRIBUTES/VARIABLE_VALUE", "bare_initializer/.ATTRIBUTES/VARIABLE_VALUE", "constant_initializer/.ATTRIBUTES/VARIABLE_VALUE", "duplicate/.ATTRIBUTES/VARIABLE_VALUE", "ones_initializer/.ATTRIBUTES/VARIABLE_VALUE", ) six.assertCountEqual( self, expected_checkpoint_names, named_variables.keys())
def testDeferredSlotRestoration(self): checkpoint_directory = self.get_temp_dir() root = checkpointable.Checkpointable() root.var = checkpointable_utils.add_variable( root, name="var", initializer=0.) optimizer = CheckpointableAdam(0.1) if context.in_graph_mode(): train_op = optimizer.minimize(root.var) self.evaluate(variables.global_variables_initializer()) self.evaluate(train_op) else: optimizer.minimize(root.var.read_value) self.evaluate(state_ops.assign(root.var, 12.)) no_slots_path = checkpointable_utils.Saver(root).save( os.path.join(checkpoint_directory, "no_slots")) root.optimizer = optimizer self.evaluate(state_ops.assign(root.var, 13.)) self.evaluate(state_ops.assign(optimizer.get_slot(name="m", var=root.var), 14.)) slots_path = checkpointable_utils.Saver(root).save( os.path.join(checkpoint_directory, "with_slots")) new_root = checkpointable.Checkpointable() # Load the slot-containing checkpoint (deferred), then immediately overwrite # the non-slot variable (also deferred). slot_status = checkpointable_utils.Saver(new_root).restore(slots_path) no_slot_status = checkpointable_utils.Saver(new_root).restore(no_slots_path) with self.assertRaises(AssertionError): no_slot_status.assert_consumed() new_root.var = checkpointable_utils.add_variable( new_root, name="var", shape=[]) no_slot_status.assert_consumed() no_slot_status.run_restore_ops() self.assertEqual(12., self.evaluate(new_root.var)) new_root.optimizer = CheckpointableAdam(0.1) with self.assertRaisesRegexp(AssertionError, "beta1_power"): slot_status.assert_consumed() self.assertEqual(12., self.evaluate(new_root.var)) if context.in_eager_mode(): # Slot variables are only created with restoring initializers when # executing eagerly. self.assertEqual(14., self.evaluate( new_root.optimizer.get_slot(name="m", var=new_root.var))) else: self.assertIs(new_root.optimizer.get_slot(name="m", var=new_root.var), None) if context.in_graph_mode(): train_op = new_root.optimizer.minimize(new_root.var) # The slot variable now exists; restore() didn't create it, but we should # now have a restore op for it. slot_status.run_restore_ops() self.assertEqual(14., self.evaluate( new_root.optimizer.get_slot(name="m", var=new_root.var))) self.evaluate(train_op) else: new_root.optimizer.minimize(new_root.var.read_value) slot_status.assert_consumed()
def testActivation(self): dense = core_layers.Dense(2, activation=nn_ops.relu, name='dense1') inputs = random_ops.random_uniform((5, 3), seed=1) outputs = dense(inputs) if context.in_graph_mode(): self.assertEqual(outputs.op.name, 'dense1/Relu') dense = core_layers.Dense(2, name='dense2') inputs = random_ops.random_uniform((5, 3), seed=1) outputs = dense(inputs) if context.in_graph_mode(): self.assertEqual(outputs.op.name, 'dense2/BiasAdd')
def test_variable_reuse_exception_nested(self): with test_util.IsolateTest(), session.Session(): first_container_variable = resource_variable_ops.ResourceVariable( name="first_container_variable", initial_value=1) if context.in_graph_mode(): self.evaluate([variables.global_variables_initializer()]) with test_util.IsolateTest(), session.Session(): if context.in_graph_mode(): with self.assertRaises(RuntimeError): self.evaluate(first_container_variable.read_value()) else: with self.assertRaises(ValueError): first_container_variable.read_value()
def doTestBasic(self, use_resource=False): for i, dtype in enumerate([dtypes.half, dtypes.float32, dtypes.float64]): with variable_scope.variable_scope("%d" % i): # Initialize variables for numpy implementation. m0, v0, m1, v1 = 0.0, 0.0, 0.0, 0.0 var0_np = np.array([1.0, 2.0], dtype=dtype.as_numpy_dtype) grads0_np = np.array([0.1, 0.1], dtype=dtype.as_numpy_dtype) var1_np = np.array([3.0, 4.0], dtype=dtype.as_numpy_dtype) grads1_np = np.array([0.01, 0.01], dtype=dtype.as_numpy_dtype) if use_resource: var0 = resource_variable_ops.ResourceVariable( var0_np, name="var0_%d" % i) var1 = resource_variable_ops.ResourceVariable( var1_np, name="var1_%d" % i) else: var0 = variables.Variable(var0_np) var1 = variables.Variable(var1_np) grads0 = constant_op.constant(grads0_np) grads1 = constant_op.constant(grads1_np) opt = adam.AdamOptimizer() update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) if context.in_graph_mode(): self.evaluate(variables.global_variables_initializer()) # Fetch params to validate initial values self.assertAllClose([1.0, 2.0], self.evaluate(var0)) self.assertAllClose([3.0, 4.0], self.evaluate(var1)) beta1_power, beta2_power = opt._get_beta_accumulators() # Run 3 steps of Adam for t in range(1, 4): if context.in_graph_mode(): self.evaluate(update) elif t > 1: opt.apply_gradients(zip([grads0, grads1], [var0, var1])) self.assertAllCloseAccordingToType(0.9**(t + 1), self.evaluate(beta1_power)) self.assertAllCloseAccordingToType(0.999**(t + 1), self.evaluate(beta2_power)) var0_np, m0, v0 = adam_update_numpy(var0_np, grads0_np, t, m0, v0) var1_np, m1, v1 = adam_update_numpy(var1_np, grads1_np, t, m1, v1) # Validate updated params self.assertAllCloseAccordingToType(var0_np, self.evaluate(var0)) self.assertAllCloseAccordingToType(var1_np, self.evaluate(var1))
def test_name_scopes_for_variable_scopes(self): # Test that name scopes are not unnecessarily uniquified (but are # still uniquified when necessary). def linear_module(x, output_size): w = variable_scope.get_variable( "w", shape=[x.get_shape()[1], output_size], initializer=init_ops.zeros_initializer()) b = variable_scope.get_variable( "b", shape=[output_size], initializer=init_ops.zeros_initializer()) return (math_ops.matmul(x, w) + b), w def make_linear_module(output_size, name): return template.make_template( name, linear_module, output_size=output_size, create_scope_now_=True) inputs = array_ops.ones((3, 4)) linear1 = make_linear_module(output_size=2, name="foo") outputs_a, w1 = linear1(inputs) outputs_b, _ = linear1(inputs) self.assertEquals("foo", linear1.variable_scope.name) self.assertEquals("foo/w:0", w1.name) if context.in_graph_mode(): self.assertEquals("foo/add:0", outputs_a.name, "First application of template should get " "same name scope as variables.") self.assertEquals("foo_1/add:0", outputs_b.name, "Second application of template should get " "a freshly uniquified name scope.") linear2 = make_linear_module(output_size=2, name="foo") outputs_c, w2 = linear2(inputs) outputs_d, _ = linear2(inputs) self.assertEquals("foo_1", linear2.variable_scope.name, "New template gets a freshly uniquified variable scope " "because 'foo' is already taken.") self.assertEquals("foo_1/w:0", w2.name) if context.in_graph_mode(): self.assertEquals("foo_1_1/add:0", outputs_c.name, "First application of template would get " "same name scope as variables, but 'foo_1' is already " "a name scope.") self.assertEquals("foo_1_2/add:0", outputs_d.name, "Second application of template should also get " "a freshly uniquified name scope.")
def _create_slots(self, var_list): # Create the beta1 and beta2 accumulators on the same device as the first # variable. Sort the var_list to make sure this device is consistent across # workers (these need to go on the same PS, otherwise some updates are # silently ignored). first_var = min(var_list, key=lambda x: x.name) create_new = self._beta1_power is None if not create_new and context.in_graph_mode(): create_new = (self._beta1_power.graph is not first_var.graph) if create_new: with ops.colocate_with(first_var): def _variable_getter(name, shape, dtype, initializer): del shape, dtype # not used, but there for compatibility return variable_scope.variable( name=name, initial_value=initializer, trainable=False) self._beta1_power = self.add_variable( name="beta1_power", shape=[], initializer=self._beta1, getter=_variable_getter) self._beta2_power = self.add_variable( name="beta2_power", shape=[], initializer=self._beta2, getter=_variable_getter) # Create slots for the first and second moments. for v in var_list: self._zeros_slot(v, "m", self._name) self._zeros_slot(v, "v", self._name)
def scatter(self, indices, value, name=None): """Scatter the values of a `Tensor` in specific indices of a `TensorArray`. Args: indices: A `1-D` `Tensor` taking values in `[0, max_value)`. If the `TensorArray` is not dynamic, `max_value=size()`. value: (N+1)-D. Tensor of type `dtype`. The Tensor to unpack. name: A name for the operation (optional). Returns: A new TensorArray object with flow that ensures the scatter occurs. Use this object all for subsequent operations. Raises: ValueError: if the shape inference fails. """ with ops.name_scope(name, "TensorArrayScatter", [self._handle, value, indices]): value = ops.convert_to_tensor(value, name="value") if self._infer_shape and context.in_graph_mode(): self._merge_element_shape(value.shape[1:]) with self._maybe_colocate_with(value): flow_out = gen_data_flow_ops._tensor_array_scatter_v3( handle=self._handle, indices=indices, value=value, flow_in=self._flow, name=name) ta = TensorArray( dtype=self._dtype, handle=self._handle, flow=flow_out, colocate_with_first_write_call=self._colocate_with_first_write_call) ta._infer_shape = self._infer_shape ta._element_shape = self._element_shape ta._colocate_with = self._colocate_with return ta
def test_no_sharing(self): with test_util.IsolateTest(), session.Session(): first_container_variable = resource_variable_ops.ResourceVariable( name="same_name", initial_value=1) if context.in_graph_mode(): self.evaluate([variables.global_variables_initializer()]) with test_util.IsolateTest(), session.Session(): second_container_variable = resource_variable_ops.ResourceVariable( name="same_name", initial_value=2) if context.in_graph_mode(): self.evaluate([variables.global_variables_initializer()]) self.assertEqual( 2, self.evaluate(second_container_variable.read_value())) self.assertEqual(1, self.evaluate(first_container_variable.read_value()))
def __init__(self, handle, dtype, handle_device, # pylint: disable=super-init-not-called shape, in_graph_mode, deleter, parent_op): # We do not call super init on purpose. self._trainable = False self._save_slice_info = None self._graph_key = ops.get_default_graph()._graph_key # pylint: disable=protected-access self._in_graph_mode = in_graph_mode self._handle = handle self._handle_device = handle_device self._shape = shape self._initial_value = None if isinstance(self._handle, ops.EagerTensor): self._handle_name = "" else: self._handle_name = self._handle.name self._dtype = dtype self._constraint = None self._cached_value = None self._is_initialized_op = None self._initializer_op = None self._parent_op = parent_op if context.in_graph_mode(): self._graph_element = self.read_value() else: self._graph_element = None self._handle_deleter = deleter
def testInputSpecNdimCheck(self): class CustomerLayer(base_layers.Layer): def __init__(self): super(CustomerLayer, self).__init__() self.input_spec = base_layers.InputSpec(ndim=2) def call(self, inputs): return inputs if context.in_graph_mode(): layer = CustomerLayer() with self.assertRaisesRegexp(ValueError, r'requires a defined rank'): layer.apply(array_ops.placeholder('int32')) layer = CustomerLayer() with self.assertRaisesRegexp(ValueError, r'expected ndim=2'): layer.apply(constant_op.constant([1])) # Note that we re-create the layer since in Eager mode, input spec checks # only happen on first call. # Works layer = CustomerLayer() layer.apply(constant_op.constant([[1], [2]]))
def testInputSpecMaxNdimCheck(self): class CustomerLayer(base_layers.Layer): def __init__(self): super(CustomerLayer, self).__init__() self.input_spec = base_layers.InputSpec(max_ndim=2) def call(self, inputs): return inputs if context.in_graph_mode(): layer = CustomerLayer() with self.assertRaisesRegexp(ValueError, r'requires a defined rank'): layer.apply(array_ops.placeholder('int32')) layer = CustomerLayer() with self.assertRaisesRegexp(ValueError, r'expected max_ndim=2'): layer.apply(constant_op.constant([[[1], [2]]])) # Works layer = CustomerLayer() layer.apply(constant_op.constant([1])) layer = CustomerLayer() layer.apply(constant_op.constant([[1], [2]]))
def assert_type(tensor, tf_type, message=None, name=None): """Statically asserts that the given `Tensor` is of the specified type. Args: tensor: A tensorflow `Tensor`. tf_type: A tensorflow type (`dtypes.float32`, `tf.int64`, `dtypes.bool`, etc). message: A string to prefix to the default message. name: A name to give this `Op`. Defaults to "assert_type" Raises: TypeError: If the tensors data type doesn't match `tf_type`. Returns: A `no_op` that does nothing. Type can be determined statically. """ message = message or '' with ops.name_scope(name, 'assert_type', [tensor]): tensor = ops.convert_to_tensor(tensor, name='tensor') if tensor.dtype != tf_type: if context.in_graph_mode(): raise TypeError( '%s %s must be of type %s' % (message, tensor.name, tf_type)) else: raise TypeError( '%s tensor must be of type %s' % (message, tf_type)) return control_flow_ops.no_op('statically_determined_correct_type')
def initialize(self, table): """Initializes the table from a text file. Args: table: The table to be initialized. Returns: The operation that initializes the table. Raises: TypeError: when the keys and values data types do not match the table key and value data types. """ _check_table_dtypes(table, self.key_dtype, self.value_dtype) with ops.name_scope(self._name, "text_file_init", (table.table_ref,)) as scope: filename = ops.convert_to_tensor( self._filename, dtypes.string, name="asset_filepath") # pylint: disable=protected-access init_op = gen_lookup_ops._initialize_table_from_text_file_v2( table.table_ref, filename, self._key_index, self._value_index, -1 if self._vocab_size is None else self._vocab_size, self._delimiter, name=scope) # pylint: enable=protected-access ops.add_to_collection(ops.GraphKeys.TABLE_INITIALIZERS, init_op) # If the filename tensor is anything other than a string constant (e.g., if # it is a placeholder) then it does not make sense to track it as an asset. if context.in_graph_mode() and constant_op.is_constant(filename): ops.add_to_collection(ops.GraphKeys.ASSET_FILEPATHS, filename) return init_op
def testRandomSeed(self): test_cases = [ # Each test case is a tuple with input to get_seed: # (input_graph_seed, input_op_seed) # and output from get_seed: # (output_graph_seed, output_op_seed) ((None, None), (None, None)), ((None, 1), (random_seed.DEFAULT_GRAPH_SEED, 1)), ((1, 1), (1, 1)), ((0, 0), (0, 2**31 - 1)), # Avoid nondeterministic (0, 0) output ((2**31 - 1, 0), (0, 2**31 - 1)), # Don't wrap to (0, 0) either ((0, 2**31 - 1), (0, 2**31 - 1)), # Wrapping for the other argument ] if context.in_graph_mode(): # 0 will be the default_graph._lastid. test_cases.append(((1, None), (1, 0))) else: # operation seed is random number generated based on global seed. # it's not tested due to possibility of platform or version difference. pass for tc in test_cases: tinput, toutput = tc[0], tc[1] random_seed.set_random_seed(tinput[0]) g_seed, op_seed = random_seed.get_seed(tinput[1]) msg = 'test_case = {0}, got {1}, want {2}'.format(tinput, (g_seed, op_seed), toutput) self.assertEqual((g_seed, op_seed), toutput, msg=msg) random_seed.set_random_seed(None)
def write_op_log(graph, log_dir, op_log=None, run_meta=None, add_trace=True): """Log provided 'op_log', and add additional model information below. The API also assigns ops in tf.trainable_variables() an op type called '_trainable_variables'. The API also logs 'flops' statistics for ops with op.RegisterStatistics() defined. flops calculation depends on Tensor shapes defined in 'graph', which might not be complete. 'run_meta', if provided, completes the shape information with best effort. Args: graph: tf.Graph. If None and eager execution is not enabled, use default graph. log_dir: directory to write the log file. op_log: (Optional) OpLogProto proto to be written. If not provided, an new one is created. run_meta: (Optional) RunMetadata proto that helps flops computation using run time shape information. add_trace: Whether to add python code trace information. Used to support "code" view. """ if not graph and context.in_graph_mode(): graph = ops.get_default_graph() op_log = merge_default_with_oplog(graph, op_log, run_meta, add_trace) with gfile.Open(os.path.join(log_dir, 'tfprof_log'), 'w') as log: log.write(op_log.SerializeToString())
def call(self, inputs, mask=None): """Call the model on new inputs. In this case `call` just reapplies all ops in the graph to the new inputs (e.g. build a new computational graph from the provided inputs). Arguments: inputs: A tensor or list of tensors. mask: A mask or list of masks. A mask can be either a tensor or None (no mask). Returns: A tensor if there is a single output, or a list of tensors if there are more than one outputs. """ inputs = nest.flatten(inputs) if mask is None: masks = [None for _ in range(len(inputs))] else: masks = nest.flatten(mask) if context.in_graph_mode(): # Try to retrieve cached outputs if the layer has already been called # on these exact inputs. cache_key = (layers_util.object_list_uid(inputs) + '_' + layers_util.object_list_uid(masks)) if cache_key in self._output_tensor_cache: # Cache hit. return self._output_tensor_cache[cache_key] # Actually apply the network graph to the new inputs. outputs, _ = self._run_internal_graph(inputs, masks) return outputs
def testMaskingSingleInput(self): class MaskedLayer(base_layers.Layer): def call(self, inputs, mask=None): if mask is not None: return inputs * mask return inputs def compute_mask(self, inputs, mask=None): return array_ops.ones_like(inputs) if context.in_graph_mode(): x = base_layers.Input(shape=(32,)) y = MaskedLayer()(x) # pylint: disable=not-callable network = base_layers.Network(x, y) # test callability on Input x_2 = base_layers.Input(shape=(32,)) y_2 = network(x_2) self.assertEqual(y_2.get_shape().as_list(), [None, 32]) # test callability on regular tensor x_2 = array_ops.placeholder(dtype='float32', shape=(None, 32)) y_2 = network(x_2) self.assertEqual(y_2.get_shape().as_list(), [None, 32]) else: a = constant_op.constant([2] * 32) mask = constant_op.constant([0, 1] * 16) a._keras_mask = mask b = MaskedLayer().apply(a) self.assertTrue(hasattr(b, '_keras_mask')) self.assertAllEqual(self.evaluate(array_ops.ones_like(mask)), self.evaluate(getattr(b, '_keras_mask'))) self.assertAllEqual(self.evaluate(a * mask), self.evaluate(b))
def _delay_checks(self): """Context manager for combining checks depending on tensor evaluations. Each call to Session.run has some overhead, and this overhead can easily account for the majority of the time spent in tests that call Session.run (or Tensor.eval) many times. This context manager provides a mechanism for registering callback functions and associated tensors. When the context is exited, all of the tensors associated with all of the registrations are evaluated with a single call to Session.run, and then each registered callback function is called with the values of its associated tensors. Yields: A function `add_check(check, *args, **kwargs)` where `check` is the callback function to be invoked, and `*args` and `**kwargs` specify the associated Tensors. When in EAGER mode, check is executed in add_check, otherwise, it's delayed after the context. """ checks = [] def add_check(check, *args, **kwargs): if context.in_eager_mode(): args_val, kwargs_val = self.evaluate([args, kwargs]) check(*args_val, **kwargs_val) else: checks.append((check, args, kwargs)) yield add_check if context.in_graph_mode(): all_values = self.evaluate([[args, kwargs] for _, args, kwargs in checks]) for (check, _, _), (args, kwargs) in zip(checks, all_values): check(*args, **kwargs)
def __init__(self, root_checkpointable): """Configure saving. Args: root_checkpointable: The root of the object graph to save/restore. This object and all of its dependencies are saved in the checkpoint. When restoring, objects are matched and restored starting from this root. """ # Allow passing in a weak reference to avoid reference cycles when # `Checkpointable` objects save themselves. self._root_checkpointable_ref = root_checkpointable if context.in_graph_mode(): self._file_prefix_placeholder = constant_op.constant("model") else: self._file_prefix_placeholder = None # Op caching for save self._object_graph_feed_tensor = None self._last_save_object_graph = None self._last_save_saver = None # Op caching for restore self._object_graph_restore_tensor = None self._last_restore_object_graph = None self._last_restore_checkpoint = None
def _create_non_slot_variable(self, initial_value, name, colocate_with): """Add an extra variable, not associated with a slot.""" if context.in_graph_mode(): graph = colocate_with.graph else: graph = None key = (name, graph) v = self._non_slot_dict.get(key, None) if v is None: with ops.colocate_with(colocate_with): def _variable_getter(name, shape, dtype, initializer): del shape, dtype # not used, but there for compatibility return variable_scope.variable( name=name, initial_value=initializer, trainable=False) initial_value = ops.convert_to_tensor(initial_value) v = self.add_variable( name=name, shape=initial_value.get_shape(), initializer=initial_value, getter=_variable_getter) self._non_slot_dict[key] = v return v
def testAgnosticUsage(self): """Graph/eager agnostic usage.""" # Does create garbage when executing eagerly due to ops.Graph() creation. num_training_steps = 10 checkpoint_directory = self.get_temp_dir() checkpoint_prefix = os.path.join(checkpoint_directory, "ckpt") for training_continuation in range(3): with ops.Graph().as_default(), self.test_session( graph=ops.get_default_graph()): network = MyNetwork() optimizer = adam.AdamOptimizer(0.001) root = checkpointable_utils.Checkpoint( optimizer=optimizer, network=network, global_step=training_util.get_or_create_global_step()) checkpoint_path = core_saver.latest_checkpoint(checkpoint_directory) status = root.restore(save_path=checkpoint_path) input_value = constant_op.constant([[3.]]) train_fn = functools.partial( optimizer.minimize, functools.partial(network, input_value), global_step=root.global_step) if context.in_graph_mode(): train_fn = functools.partial(self.evaluate, train_fn()) status.initialize_or_restore() for _ in range(num_training_steps): train_fn() root.save(file_prefix=checkpoint_prefix) self.assertEqual((training_continuation + 1) * num_training_steps, self.evaluate(root.global_step)) self.assertEqual(training_continuation + 1, self.evaluate(root.save_counter))
def call(self, inputs, training=None): if training is None: training = K.learning_phase() output = super(BatchNormalization, self).call(inputs, training=training) if context.in_graph_mode() and training is K.learning_phase(): output._uses_learning_phase = True # pylint: disable=protected-access return output
def create_slot_with_initializer(primary, initializer, shape, dtype, name, colocate_with_primary=True): """Creates a slot initialized using an `Initializer`. The type of the slot is determined by the given value. Args: primary: The primary `Variable` or `Tensor`. initializer: An `Initializer`. The initial value of the slot. shape: Shape of the initial value of the slot. dtype: Type of the value of the slot. name: Name to use for the slot variable. colocate_with_primary: Boolean. If True the slot is located on the same device as `primary`. Returns: A `Variable` object. """ # Scope the slot name in the namespace of the primary variable. # Set "primary.op.name + '/' + name" as default name, so the scope name of # optimizer can be shared when reuse is True. Meanwhile when reuse is False # and the same name has been previously used, the scope name will add '_N' # as suffix for unique identifications. validate_shape = shape.is_fully_defined() prefix = primary.op.name if context.in_graph_mode() else primary._shared_name # pylint: disable=protected-access with variable_scope.variable_scope(None, prefix + "/" + name): if colocate_with_primary: with ops.colocate_with(primary): return _create_slot_var(primary, initializer, "", validate_shape, shape, dtype) else: return _create_slot_var(primary, initializer, "", validate_shape, shape, dtype)
def split(self, value, lengths, name=None): """See TensorArray.""" with ops.name_scope(name, "TensorArraySplit", [self._handle, value, lengths]): value = ops.convert_to_tensor(value, name="value") with self._maybe_colocate_with(value): lengths_64 = math_ops.to_int64(lengths) if self._infer_shape and context.in_graph_mode(): clengths = tensor_util.constant_value(lengths_64) if value.shape.dims is not None: if clengths is not None and clengths.max() == clengths.min(): self._merge_element_shape( tensor_shape.TensorShape([clengths[0]]).concatenate( value.shape[1:])) flow_out = gen_data_flow_ops._tensor_array_split_v3( handle=self._handle, value=value, lengths=lengths_64, flow_in=self._flow, name=name) ta = TensorArray( dtype=self._dtype, handle=self._handle, flow=flow_out, colocate_with_first_write_call=self._colocate_with_first_write_call) ta._infer_shape = self._infer_shape ta._element_shape = self._element_shape ta._colocate_with = self._colocate_with return ta
def _init_from_proto(self, variable_def, import_scope=None): """Initializes from `VariableDef` proto.""" # Note that init_from_proto is currently not supported in Eager mode. assert context.in_graph_mode() self._in_graph_mode = True assert isinstance(variable_def, variable_pb2.VariableDef) if not variable_def.is_resource: raise ValueError("Trying to restore Variable as ResourceVariable.") # Create from variable_def. g = ops.get_default_graph() self._handle = g.as_graph_element( ops.prepend_name_scope( variable_def.variable_name, import_scope=import_scope)) self._handle_device = self._handle.device self._handle_name = self._handle.name self._initializer_op = g.as_graph_element( ops.prepend_name_scope( variable_def.initializer_name, import_scope=import_scope)) if variable_def.snapshot_name: self._cached_value = g.as_graph_element( ops.prepend_name_scope( variable_def.snapshot_name, import_scope=import_scope)) else: self._cached_value = None if variable_def.HasField("save_slice_info_def"): self._save_slice_info = variables.Variable.SaveSliceInfo( save_slice_info_def=variable_def.save_slice_info_def) else: self._save_slice_info = None self._caching_device = None self._dtype = dtypes.as_dtype(self._handle.op.get_attr("dtype")) self._graph_element = self.value() self._constraint = None
def new_func(*args, **kwargs): """Deprecation wrapper.""" # TODO(apassos) figure out a way to have reasonable performance with # deprecation warnings and eager mode. if context.in_graph_mode() and _PRINT_DEPRECATION_WARNINGS: invalid_args = [] named_args = tf_inspect.getcallargs(func, *args, **kwargs) for arg_name, spec in iter(deprecated_positions.items()): if (spec.position < len(args) and not (spec.has_ok_value and _same_value(named_args[arg_name], spec.ok_value))): invalid_args.append(arg_name) if is_varargs_deprecated and len(args) > len(arg_spec.args): invalid_args.append(arg_spec.varargs) if is_kwargs_deprecated and kwargs: invalid_args.append(arg_spec.keywords) for arg_name in deprecated_arg_names: if (arg_name in kwargs and not (deprecated_positions[arg_name].has_ok_value and _same_value(named_args[arg_name], deprecated_positions[arg_name].ok_value))): invalid_args.append(arg_name) for arg_name in invalid_args: if (func, arg_name) not in _PRINTED_WARNING: if warn_once: _PRINTED_WARNING[(func, arg_name)] = True logging.warning( 'From %s: calling %s (from %s) with %s is deprecated and will ' 'be removed %s.\nInstructions for updating:\n%s', _call_location(), decorator_utils.get_qualified_name(func), func.__module__, arg_name, 'in a future version' if date is None else ('after %s' % date), instructions) return func(*args, **kwargs)
def _get_beta_accumulators(self): if context.in_graph_mode(): graph = ops.get_default_graph() else: graph = None return (self._get_non_slot_variable("beta1_power", graph=graph), self._get_non_slot_variable("beta2_power", graph=graph))
def __call__(self, *args): """Executes the passed function in eager mode.""" tensor_inputs = [ x for x in nest.flatten(args) if isinstance(x, ops.Tensor) ] if tape.should_record(tensor_inputs) or tape.should_record( self._extra_inputs): if not self._has_backprop: self._compute_backprop() return self._backprop_call(tensor_inputs) if context.in_graph_mode(): g = ops.get_default_graph() if self._fdef.name not in g._functions: # pylint: disable=protected-access g._add_function(self._fdef) # pylint: disable=protected-access signature = self._fdef.definition.signature args = list(tensor_inputs) + self._extra_inputs op = g.create_op( signature.name, [ops.convert_to_tensor(x) for x in args], [dtypes.DType(x.type) for x in signature.output_arg], op_def=signature, name="FunctionCall", compute_shapes=False) result = op.outputs for i, s in enumerate(self._output_shapes): result[i].set_shape(s) else: result = execute.execute( str(self._func_name), num_outputs=self._num_outputs, inputs=tensor_inputs + self._extra_inputs) return self._build_call_outputs(self._returns, result)
def init_variables(self): """Initializes this Metric's variables. Should be called after variables are created in the first execution of `__call__()`. If using graph execution, the return value should be `run()` in a session before running the op returned by `__call__()`. (See example above.) Returns: If using graph execution, this returns an op to perform the initialization. Under eager execution, the variables are reset to their initial values as a side effect and this function returns None. """ if context.in_graph_mode(): return control_flow_ops.group([v.initializer for v in self._vars]) for v in self._vars: v.assign(self._initial_values[v])
def testBatchSizeFromInput(self): cell = Plus1RNNCell() in_graph_mode = context.in_graph_mode() # With static batch size if in_graph_mode: inputs = array_ops.placeholder(dtypes.float32, shape=(3, 4, 5)) initial_state = array_ops.placeholder(dtypes.float32, shape=(3, 5)) else: inputs = np.zeros((3, 4, 5), dtype=np.float32) initial_state = np.zeros((3, 5), dtype=np.float32) # - Without initial_state outputs, state = rnn.dynamic_rnn(cell, inputs, dtype=dtypes.float32) if in_graph_mode: self.assertEqual(3, outputs.shape[0].value) self.assertEqual(3, state.shape[0].value) else: self.assertEqual(3, outputs.shape[0]) self.assertEqual(3, state.shape[0]) # - With initial_state outputs, state = rnn.dynamic_rnn( cell, inputs, initial_state=initial_state) if in_graph_mode: self.assertEqual(3, outputs.shape[0].value) self.assertEqual(3, state.shape[0].value) else: self.assertEqual(3, outputs.shape[0]) self.assertEqual(3, state.shape[0]) # Without static batch size # Tensor shapes are fully determined in Eager mode, so only run this # test in graph mode. if in_graph_mode: inputs = array_ops.placeholder(dtypes.float32, shape=(None, 4, 5)) # - Without initial_state outputs, state = rnn.dynamic_rnn(cell, inputs, dtype=dtypes.float32) self.assertEqual(None, outputs.shape[0].value) self.assertEqual(None, state.shape[0].value) # - With initial_state outputs, state = rnn.dynamic_rnn( cell, inputs, initial_state=array_ops.placeholder(dtypes.float32, shape=(None, 5))) self.assertEqual(None, outputs.shape[0].value) self.assertEqual(None, state.shape[0].value)
def call(self, inputs): inputs = ops.convert_to_tensor(inputs, dtype=self.dtype) shape = inputs.get_shape().as_list() if len(shape) > 2: # Broadcasting is required for the inputs. outputs = standard_ops.tensordot(inputs, self.kernel, [[len(shape) - 1], [0]]) # Reshape the output back to the original ndim of the input. if context.in_graph_mode(): output_shape = shape[:-1] + [self.units] outputs.set_shape(output_shape) else: outputs = standard_ops.matmul(inputs, self.kernel) outputs = nn.bias_add(outputs, self.bias) return outputs
def _ExtractInputShapes(inputs): """Extract the shapes of a set of input tensors.""" sizes = [] fully_known = True for x in inputs: input_shape = array_ops.shape(x) if context.in_graph_mode(): if not isinstance(input_shape, ops.Tensor) or input_shape.op.type != "Const": fully_known = False break sizes.append(input_shape) if fully_known: return sizes else: return array_ops.shape_n(inputs)
def _create_non_slot_variable(self, initial_value, name, colocate_with): """Add an extra variable, not associated with a slot.""" if context.in_graph_mode(): graph = colocate_with.graph else: graph = None key = (name, graph) v = self._non_slot_dict.get(key, None) if v is None: with ops.colocate_with(colocate_with): v = variable_scope.variable(initial_value, name=name, trainable=False) self._non_slot_dict[key] = v return v
def testNoInputSpec(self): class CustomerLayer(base_layers.Layer): def __init__(self): super(CustomerLayer, self).__init__() self.input_spec = None def call(self, inputs): return inputs layer = CustomerLayer() layer.apply(constant_op.constant(1)) # Works if context.in_graph_mode(): layer.apply(array_ops.placeholder('int32')) layer.apply(array_ops.placeholder('int32', shape=(2, 3)))
def _create_slots(self, var_list): first_var = min(var_list, key=lambda x: x.name) create_new = self._beta1_power is None if not create_new and context.in_graph_mode(): create_new = (self._beta1_power.graph is not first_var.graph) if create_new: with ops.colocate_with(first_var): self._beta1_power = variable_scope.variable(self._beta1, name="beta1_power", trainable=False) self._beta2_power = variable_scope.variable(self._beta2, name="beta2_power", trainable=False) self._gamma_multi = variable_scope.variable(self._gamma, name="gamma_multi", trainable=False) # Create slots for the first and second moments. for v in var_list : self._zeros_slot(v, "m", self._name) self._zeros_slot(v, "v", self._name) self._zeros_slot(v, "vhat", self._name)
def _init_from_proto(self, variable_def, import_scope=None): """Initializes from `VariableDef` proto.""" # Note that init_from_proto is currently not supported in Eager mode. assert context.in_graph_mode() self._in_graph_mode = True assert isinstance(variable_def, variable_pb2.VariableDef) if not variable_def.is_resource: raise ValueError("Trying to restore Variable as ResourceVariable.") # Create from variable_def. g = ops.get_default_graph() self._handle = g.as_graph_element( ops.prepend_name_scope(variable_def.variable_name, import_scope=import_scope)) self._shape = tensor_shape.TensorShape( self._handle.op.get_attr("shape")) self._handle_name = self._handle.name self._initializer_op = g.as_graph_element( ops.prepend_name_scope(variable_def.initializer_name, import_scope=import_scope)) # Check whether initial_value_name exists for backwards compatibility. if (hasattr(variable_def, "initial_value_name") and variable_def.initial_value_name): self._initial_value = g.as_graph_element( ops.prepend_name_scope(variable_def.initial_value_name, import_scope=import_scope)) else: self._initial_value = None if variable_def.snapshot_name: self._cached_value = g.as_graph_element( ops.prepend_name_scope(variable_def.snapshot_name, import_scope=import_scope)) else: self._cached_value = None if variable_def.HasField("save_slice_info_def"): self._save_slice_info = variables.Variable.SaveSliceInfo( save_slice_info_def=variable_def.save_slice_info_def, import_scope=import_scope) else: self._save_slice_info = None self._caching_device = None self._dtype = dtypes.as_dtype(self._handle.op.get_attr("dtype")) self._graph_element = g.get_tensor_by_name(self._handle.op.name + "/Read/ReadVariableOp:0") self._constraint = None self._cached_shape_as_list = None
def merge_default_with_oplog(graph, op_log=None, run_meta=None, add_trace=True, add_trainable_var=True): """Merge the tfprof default extra info with caller's op_log. Args: graph: tf.Graph. If None and eager execution is not enabled, use default graph. op_log: OpLogProto proto. run_meta: RunMetadata proto used to complete shape information. add_trace: Whether to add op trace information. add_trainable_var: Whether to assign tf.trainable_variables() op type '_trainable_variables'. Returns: tmp_op_log: Merged OpLogProto proto. """ if not graph and context.in_graph_mode(): graph = ops.get_default_graph() tmp_op_log = tfprof_log_pb2.OpLogProto() if not graph: return tmp_op_log logged_ops, string_to_id = _get_logged_ops( graph, run_meta, add_trace=add_trace, add_trainable_var=add_trainable_var) if not op_log: tmp_op_log.log_entries.extend(logged_ops.values()) else: all_ops = dict() for entry in op_log.log_entries: all_ops[entry.name] = entry for op_name, entry in six.iteritems(logged_ops): if op_name in all_ops: all_ops[op_name].types.extend(entry.types) if entry.float_ops > 0 and all_ops[op_name].float_ops == 0: all_ops[op_name].float_ops = entry.float_ops if entry.code_def.traces and not all_ops[op_name].code_def.traces: all_ops[op_name].code_def.MergeFrom(entry.code_def) else: all_ops[op_name] = entry tmp_op_log.log_entries.extend(all_ops.values()) for s, i in six.iteritems(string_to_id): tmp_op_log.id_to_string[i] = s return tmp_op_log
def restore(self, sess, save_path, var_filter=lambda v: True): """Restores only variables that are contained in `save_path` and match in shape and dtype and return `True` when passed to `var_filter`.""" if self._is_empty: return if save_path is None: raise ValueError("Can't load save_path when it is None.") logging.info("Restoring parameters from %s", save_path) reader = tf.train.load_checkpoint(save_path) shape_map = reader.get_variable_to_shape_map() dtype_map = reader.get_variable_to_dtype_map() restore_op_name = self.saver_def.restore_op_name restore_op_grouped = sess.graph.get_operation_by_name(restore_op_name) restore_ops = [] for r_op in restore_op_grouped.control_inputs: v = r_op.inputs[0] tensor_name = v.op.name tensor_shape = v.get_shape().as_list() tensor_dtype = v.dtype.base_dtype if tensor_name not in shape_map or tensor_name not in dtype_map: logging.warn('variable %s not in checkpoint', tensor_name) elif shape_map[tensor_name] != tensor_shape: logging.warn( 'variable %s in checkpoint, but checkpoint shape %r does not match graph shape %r', tensor_name, shape_map[tensor_name], tensor_shape) elif dtype_map[tensor_name] != tensor_dtype: logging.warn( 'variable %s in checkpoint, but checkpoint dtype %r does not match graph dtype %r', tensor_name, dtype_map[tensor_name], tensor_dtype) elif not var_filter(v): logging.info('variable %s rejected by var_filter', tensor_name, dtype_map[tensor_name], tensor_dtype) else: restore_ops.append(r_op) logging.info('adding variable %s to be restored', tensor_name) if context.in_graph_mode(): for r_op in restore_ops: sess.run(r_op, {self.saver_def.filename_tensor_name: save_path}) else: raise NotImplementedError( "eager selective restoring not supprted yet")
def _IndexedSlicesToTensor(value, dtype=None, name=None, as_ref=False): """Converts an IndexedSlices object `value` to a Tensor. NOTE(mrry): This function is potentially expensive. Args: value: An ops.IndexedSlices object. dtype: The dtype of the Tensor to be returned. name: Optional name to use for the returned Tensor. as_ref: True if a ref is requested. Returns: A dense Tensor representing the values in the given IndexedSlices. Raises: ValueError: If the IndexedSlices does not have the same dtype. """ _ = as_ref if dtype and not dtype.is_compatible_with(value.dtype): raise ValueError( "Tensor conversion requested dtype %s for IndexedSlices with dtype %s" % (dtype.name, value.dtype.name)) if value.dense_shape is None: raise ValueError( "Tensor conversion requested for IndexedSlices without dense_shape: %s" % str(value)) # TODO(mrry): Consider adding static shape information to # IndexedSlices, to avoid using numpy here. if context.in_graph_mode(): dense_shape_value = tensor_util.constant_value(value.dense_shape) if dense_shape_value is not None: num_elements = np.prod(dense_shape_value) if num_elements >= _LARGE_SPARSE_NUM_ELEMENTS: warnings.warn( "Converting sparse IndexedSlices to a dense Tensor with %d " "elements. This may consume a large amount of memory." % num_elements) else: warnings.warn( "Converting sparse IndexedSlices to a dense Tensor of unknown shape. " "This may consume a large amount of memory.") return math_ops.unsorted_segment_sum(value.values, value.indices, value.dense_shape[0], name=name)
def call(self, inputs): inputs = ops.convert_to_tensor(inputs, dtype=self.dtype) shape = inputs.get_shape().as_list() if len(shape) > 2: # Broadcasting is required for the inputs. outputs = standard_ops.tensordot(inputs, self.kernel, [[len(shape) - 1], [0]]) # Reshape the output back to the original ndim of the input. if context.in_graph_mode(): output_shape = shape[:-1] + [self.units] outputs.set_shape(output_shape) else: outputs = gen_math_ops.mat_mul(inputs, self.kernel) if self.use_bias: outputs = nn.bias_add(outputs, self.bias) if self.activation is not None: return self.activation(outputs) # pylint: disable=not-callable return outputs
def restore(save_path, root_checkpointable, object_graph_proto, session=None): """Restore a training checkpoint. Restores the values of variables created with `Checkpointable.add_variable` in the dependency graph of `root_checkpointable`. Either assigns values immediately (if variables to restore have been created already), or defers restoration until the variables are created. When building a graph, restorations are executed in the default session if `session` is `None`. Variable initializers read checkpointed values. Args: save_path: The path to the checkpoint, as returned by `save` or `tf.train.latest_checkpoint`. If None (as when there is no latest checkpoint for `tf.train.latest_checkpoint` to return), does nothing. root_checkpointable: The root of the object graph to restore. Variables to restore need not have been created yet, but all dependencies on other Checkpointable objects should already be declared. Objects in the dependency graph are matched to objects in the checkpointed graph, and matching objects have their variables restored (or the checkpointed values saved for eventual restoration when the variable is created). object_graph_proto: (Temporary) the checkpointed object graph. This will eventually be saved with the checkpoint, and will not be part of the final API. session: The session to evaluate assignment ops in. Ignored when executing eagerly. If not provided when graph building, the default session is used. """ if save_path is None: return object_id_map = _checkpoint_object_id_map(root_checkpointable, object_graph_proto) reader = training.NewCheckpointReader(save_path) dtype_map = reader.get_variable_to_dtype_map() if context.in_graph_mode(): if session is None: session = ops.get_default_session() else: session = None for restoration, checkpointable in _gather_restorations(object_graph_proto, save_path, object_id_map, dtype_map, session=session): checkpointable._process_restoration(restoration) # pylint: disable=protected-access
def decorated(*args, **kwargs): """Decorated function with custom gradient.""" if context.in_graph_mode(): if kwargs: raise ValueError( "custom_gradient in graph mode doesn't support keyword arguments." ) name = "CustomGradient-%s" % tf_ops.uid() args = [tf_ops.convert_to_tensor(x) for x in args] result, grad_fn = f(*args) flat_result = nest.flatten(result) all_tensors = flat_result + args @tf_ops.RegisterGradient(name) def internal_grad_fn(unused_op, *result_grads): # pylint: disable=unused-variable gradients = nest.flatten( grad_fn(*result_grads[:len(flat_result)])) # Need to return one value per input to the IdentityN, so pad the # gradients of the inputs of the custom_gradient function with the # gradients of the outputs as well. return ([None] * len(flat_result)) + gradients with tf_ops.get_default_graph().gradient_override_map( {"IdentityN": name}): all_tensors = array_ops.identity_n(all_tensors) return nest.pack_sequence_as( structure=result, flat_sequence=all_tensors[:len(flat_result)]) input_tensors = [x for x in args if isinstance(x, tf_ops.Tensor)] with tape.stop_recording(): result, grad_fn = f(*args, **kwargs) # TODO(apassos): naive uses of custom_gradient will not get the correct # second derivative this way if they capture any output tensors. Change the # signature of custom_gradient. def actual_grad_fn(*outputs): return nest.flatten(grad_fn(*outputs)) flat_result = nest.flatten(result) tape.record_operation(f.__name__, flat_result, input_tensors, [], actual_grad_fn) flat_result = list(flat_result) return result
def get_seed(op_seed): """Returns the local seeds an operation should use given an op-specific seed. Given operation-specific seed, `op_seed`, this helper function returns two seeds derived from graph-level and op-level seeds. Many random operations internally use the two seeds to allow user to change the seed globally for a graph, or for only specific operations. For details on how the graph-level seed interacts with op seeds, see @{tf.set_random_seed}. Args: op_seed: integer. Returns: A tuple of two integers that should be used for the local seed of this operation. """ is_graph_mode = context.in_graph_mode() if is_graph_mode: global_seed = ops.get_default_graph().seed else: global_seed = context.global_seed() if global_seed is not None: if op_seed is None: # pylint: disable=protected-access if is_graph_mode: op_seed = ops.get_default_graph()._last_id else: op_seed = context.internal_operation_seed() seeds = _truncate_seed(global_seed), _truncate_seed(op_seed) else: if op_seed is not None: seeds = DEFAULT_GRAPH_SEED, _truncate_seed(op_seed) else: seeds = None, None # Avoid (0, 0) as the C++ ops interpret it as nondeterminism, which would # be unexpected since Python docs say nondeterminism is (None, None). if seeds == (0, 0): return (0, _MAXINT32) return seeds
def save(file_prefix, root_checkpointable, checkpoint_number=None, session=None): """Save a training checkpoint. Args: file_prefix: A prefix to use for the checkpoint filenames (/path/to/directory/and_a_prefix). Names are generated based on this prefix and the global step, if provided. root_checkpointable: A Checkpointable object to save. The checkpoint includes variables created by this object and any Checkpointable objects it depends on. checkpoint_number: An integer variable or Tensor, used to number checkpoints. Typically this value is saved along with other variables in training checkpoints, which will happen automatically if it was created by `root_checkpointable` or one of its dependencies (via `Checkpointable._add_variable`). session: The session to evaluate variables in. Ignored when executing eagerly. If not provided when graph building, the default session is used. Returns: The full path to the checkpoint. """ named_variables, serialized_graph = _serialize_object_graph( root_checkpointable) if context.in_graph_mode(): if session is None: session = ops.get_default_session() else: session = None assert _OBJECT_GRAPH_PROTO_KEY not in named_variables # TODO(allenl): Feed rather than embedding a constant. named_variables[_OBJECT_GRAPH_PROTO_KEY] = _NoRestoreSaveable( tensor=constant_op.constant(serialized_graph.SerializeToString(), dtype=dtypes.string), name=_OBJECT_GRAPH_PROTO_KEY) with ops.device("/device:CPU:0"): save_path = saver_lib.Saver(var_list=named_variables).save( sess=session, save_path=file_prefix, write_meta_graph=False, global_step=checkpoint_number) return save_path
def __init__(self, graph=None, op_log=None): """Constructor. Args: graph: tf.Graph. If None and eager execution is not enabled, use default graph. op_log: optional. tensorflow::tfprof::OpLogProto proto. Used to define extra op types. """ if not graph and context.in_graph_mode(): graph = ops.get_default_graph() self._coverage = 0.0 self._graph = graph # pylint: disable=protected-access op_log = tfprof_logger.merge_default_with_oplog( self._graph, op_log=op_log) # pylint: enable=protected-access print_mdl.NewProfiler( _graph_string(self._graph), op_log.SerializeToString())
def testSharedName(self): v = resource_variable_ops.ResourceVariable(300.0, name="var1") self.evaluate(variables.global_variables_initializer()) w = resource_variable_ops.var_handle_op( dtype=v.dtype.base_dtype, shape=v.get_shape(), shared_name="var1") w_read = resource_variable_ops.read_variable_op(w, v.dtype.base_dtype) self.assertEqual(300.0, self.evaluate(w_read)) x = resource_variable_ops.var_handle_op( dtype=v.dtype.base_dtype, shape=v.get_shape(), shared_name="var2") if context.in_graph_mode(): with self.assertRaisesOpError("Resource .*/var2/.* does not exist"): x_read = resource_variable_ops.read_variable_op(x, v.dtype.base_dtype) self.evaluate(x_read) else: with self.assertRaisesRegexp(errors.NotFoundError, "Attempted to read a nonexistent variable."): _ = resource_variable_ops.read_variable_op(x, v.dtype.base_dtype)
def decorated(*args, **kwargs): """Decorated function with custom gradient.""" if context.in_graph_mode(): if kwargs: raise ValueError( "custom_gradient in graph mode doesn't support keyword arguments." ) name = "CustomGradient-%s" % tf_ops.uid() args = [tf_ops.convert_to_tensor(x) for x in args] result, grad_fn = f(*args) flat_result = nest.flatten(result) all_tensors = flat_result + args @tf_ops.RegisterGradient(name) def internal_grad_fn(unused_op, *result_grads): # pylint: disable=unused-variable gradients = nest.flatten( grad_fn(*result_grads[:len(flat_result)])) # Need to return one value per input to the IdentityN, so pad the # gradients of the inputs of the custom_gradient function with the # gradients of the outputs as well. return ([None] * len(flat_result)) + gradients with tf_ops.get_default_graph().gradient_override_map( {"IdentityN": name}): all_tensors = array_ops.identity_n(all_tensors) return nest.pack_sequence_as( structure=result, flat_sequence=all_tensors[:len(flat_result)]) input_tensors = [tf_ops.convert_to_tensor(x) for x in args] with tape.stop_recording(): result, grad_fn = f(*args, **kwargs) flat_result = nest.flatten(result) # TODO (apassos) consider removing the identity below. id:3150 gh:3151 flat_result = [gen_array_ops.identity(x) for x in flat_result] def actual_grad_fn(*outputs): return nest.flatten(grad_fn(*outputs)) tape.record_operation(f.__name__, flat_result, input_tensors, actual_grad_fn) flat_result = list(flat_result) return nest.pack_sequence_as(result, flat_result)
def save(self, file_prefix, session=None): """Save a checkpoint. Wraps `tfe.CheckpointableSaver.save`.""" in_graph_mode = context.in_graph_mode() if in_graph_mode: if session is None: session = ops.get_default_session() if self._save_counter is None: # When graph building, if this is a new save counter variable then it # needs to be initialized before assign_add. This is only an issue if # restore() has not been called first. session.run(self.save_counter.initializer) with ops.colocate_with(self.save_counter): assign_op = self.save_counter.assign_add(1) if in_graph_mode: session.run(assign_op) return self._saver.save( file_prefix=file_prefix, checkpoint_number=self.save_counter, session=session)
def __init__(self, var_list): """A tf.train.Saver adapter for use when eager execution is enabled. The API, and on-disk format, mimic tf.train.Saver except that no Session is needed. Args: var_list: The list of variables that will be saved and restored. Either a list of `tfe.Variable` objects, or a dictionary mapping names to `tfe.Variable` objects. Raises: RuntimeError: if invoked when eager execution has not been enabled. """ if context.in_graph_mode(): raise RuntimeError("tfe.Saver can only be used when eager " "execution is enabled. Use tf.train.Saver when " "building graphs.") self._saver = _saver.Saver(var_list=var_list)
def testDeepCopy(self): class MyLayer(base_layers.Layer): def call(self, inputs): return math_ops.square(inputs) layer = MyLayer(name='my_layer') layer._private_tensor = random_ops.random_uniform(()) inputs = random_ops.random_uniform((5, ), seed=1) outputs = layer.apply(inputs) self.assertEqual(layer.built, True) if context.in_graph_mode(): # op only supported in GRAPH mode. self.assertEqual(outputs.op.name, 'my_layer/Square') layer_copy = copy.deepcopy(layer) self.assertEqual(layer_copy.name, layer.name) self.assertEqual(layer_copy._scope.name, layer._scope.name) self.assertEqual(layer_copy._graph, layer._graph) self.assertEqual(layer_copy._private_tensor, layer._private_tensor)
def add_to_graph(self, g): """Adds this function into the graph g.""" self._create_definition_if_needed() # Adds this function into 'g'. # pylint: disable=protected-access if context.in_graph_mode(): g._add_function(self) else: context.context().add_function_def(self.definition) # pylint: enable=protected-access # Ensures related sub-routines are defined in 'g', too. for f in self._sub_functions.values(): f.add_to_graph(g) # Adds its gradient function, too. if self._grad_func: self._grad_func.add_to_graph(g)
def _backprop_call(self, args): """Calls the wrapped function and records the result on a tape.""" all_args = args + self._extra_inputs signature = self._forward_fdef.definition.signature if context.in_graph_mode(): g = ops.get_default_graph() g._add_function(self._forward_fdef) # pylint: disable=protected-access unwrapped_args = [ag_core.getval(x) for x in all_args] op = g.create_op( signature.name, [ops.convert_to_tensor(x) for x in unwrapped_args], [dtypes.DType(x.type) for x in signature.output_arg], op_def=signature, name="FunctionCall", compute_shapes=False) outputs = op.outputs outputs = [outputs] if isinstance(outputs, (tensor.Tensor, ops.Tensor, type(None))) else list(outputs) for i, s in enumerate(self._output_shapes): outputs[i].set_shape(s) else: outputs = execute.execute(signature.name, num_outputs=len(signature.output_arg), inputs=all_args) real_outputs = outputs[:len(self._returns)] side_outputs = outputs[len(self._returns):] watched_extra_inputs = [] for t in self._extra_inputs: tid = ops.tensor_id(t) for t in tape._tape_stack.stack: # pylint: disable=protected-access w = t.value.tensors.get(tid, None) if w is not None: watched_extra_inputs.append(w) break else: # Note: for-else here done on purpose watched_extra_inputs.append(t) real_outputs = tape.record_operation(real_outputs, (args + watched_extra_inputs), side_outputs, self._backward_function) return self._build_call_outputs(self._returns, real_outputs)
def scatter(self, indices, value, name=None): """Scatter the values of a `Tensor` in specific indices of a `TensorArray`. Args: indices: A `1-D` `Tensor` taking values in `[0, max_value)`. If the `TensorArray` is not dynamic, `max_value=size()`. value: (N+1)-D. Tensor of type `dtype`. The Tensor to unpack. name: A name for the operation (optional). Returns: A new TensorArray object with flow that ensures the scatter occurs. Use this object all for subsequent operations. Raises: ValueError: if the shape inference fails. """ with ops.name_scope(name, "TensorArrayScatter", [self._handle, value, indices]): value = ops.convert_to_tensor(value, name="value") with self._maybe_colocate_with(value): flow_out = gen_data_flow_ops._tensor_array_scatter_v3( handle=self._handle, indices=indices, value=value, flow_in=self._flow, name=name) ta = TensorArray(dtype=self._dtype, handle=self._handle, flow=flow_out, colocate_with_first_write_call=self. _colocate_with_first_write_call) ta._infer_shape = self._infer_shape ta._element_shape = self._element_shape ta._colocate_with = self._colocate_with if ta._infer_shape and context.in_graph_mode(): val_shape = flow_out.op.inputs[2].get_shape() element_shape = tensor_shape.unknown_shape() if val_shape.dims is not None: element_shape = tensor_shape.TensorShape( val_shape.dims[1:]) ta._merge_element_shape(element_shape) return ta
def testDictInputOutput(self): class DictLayer(base_layers.Layer): def call(self, inputs): return {'l' + key: inputs[key] for key in inputs} layer = DictLayer() if context.in_graph_mode(): i1 = array_ops.placeholder('int32') i2 = array_ops.placeholder('float32') result = layer.apply({'abel': i1, 'ogits': i2}) self.assertTrue(isinstance(result, dict)) self.assertEqual(set(['label', 'logits']), set(result.keys())) else: i1 = constant_op.constant(3) i2 = constant_op.constant(4.0) result = layer.apply({'abel': i1, 'ogits': i2}) self.assertTrue(isinstance(result, dict)) self.assertEqual(set(['label', 'logits']), set(result.keys())) self.assertEqual(3, result['label'].numpy()) self.assertEqual(4.0, result['logits'].numpy())
def __init__(self, name=None): self._built = False self._vars = [] self._updates = [] name = name or self.__class__.__name__ # Replace things like spaces in name to create a valid scope name. scope_name = _to_replace.sub("_", name) # We create the variable scope now to get the unique name that will # be used as a variable prefix when build() calls add_variable(). with variable_scope.variable_scope(None, default_name=scope_name, use_resource=True, reuse=False) as scope: pos = scope.name.rfind(scope_name) self._name = name + scope.name[pos + len(scope_name):] self._scope = scope if context.in_graph_mode(): # We make self.call() into a graph callable here, so that we can # return a single op that performs all of the variable updates. self.call = function.defun(self.call)
def _TileGrad(op, grad): """Sum reduces grad along the tiled dimensions.""" assert isinstance(grad, ops.Tensor) input_shape = array_ops.shape(op.inputs[0]) # We interleave multiples and input_shape to get split_shape, # reshape grad to split_shape, and reduce along all even # dimensions (the tiled dimensions) to get the result # with shape input_shape. For example # input_shape = [20, 30, 40] # multiples = [2, 3, 4] # split_shape = [2, 20, 3, 30, 4, 40] # axes = [0, 2, 4] split_shape = array_ops.reshape( array_ops.transpose(array_ops.stack([op.inputs[1], input_shape])), [-1]) axes = math_ops.range(0, array_ops.size(split_shape), 2) input_grad = math_ops.reduce_sum(array_ops.reshape(grad, split_shape), axes) # Fix shape inference if context.in_graph_mode(): input_grad.set_shape(op.inputs[0].get_shape()) return [input_grad, None]
def split(self, value, lengths, name=None): """Split the values of a `Tensor` into the TensorArray. Args: value: (N+1)-D. Tensor of type `dtype`. The Tensor to split. lengths: 1-D. int32 vector with the lengths to use when splitting `value` along its first dimension. name: A name for the operation (optional). Returns: A new TensorArray object with flow that ensures the split occurs. Use this object all for subsequent operations. Raises: ValueError: if the shape inference fails. """ with ops.name_scope(name, "TensorArraySplit", [self._handle, value, lengths]): value = ops.convert_to_tensor(value, name="value") with self._maybe_colocate_with(value): lengths_64 = math_ops.to_int64(lengths) if self._infer_shape and context.in_graph_mode(): clengths = tensor_util.constant_value(lengths_64) if value.shape.dims is not None: if clengths is not None and clengths.max() == clengths.min(): self._merge_element_shape( tensor_shape.TensorShape([clengths[0]]).concatenate( value.shape[1:])) flow_out = gen_data_flow_ops._tensor_array_split_v3( handle=self._handle, value=value, lengths=lengths_64, flow_in=self._flow, name=name) ta = TensorArray( dtype=self._dtype, handle=self._handle, flow=flow_out, colocate_with_first_write_call=self._colocate_with_first_write_call) ta._infer_shape = self._infer_shape ta._element_shape = self._element_shape ta._colocate_with = self._colocate_with return ta
def scatter(self, indices, value, name=None): """See TensorArray.""" with ops.name_scope(name, "TensorArrayScatter", [self._handle, value, indices]): value = ops.convert_to_tensor(value, name="value") if self._infer_shape and context.in_graph_mode(): self._merge_element_shape(value.shape[1:]) with self._maybe_colocate_with(value): flow_out = gen_data_flow_ops.tensor_array_scatter_v3( handle=self._handle, indices=indices, value=value, flow_in=self._flow, name=name) ta = TensorArray( dtype=self._dtype, handle=self._handle, flow=flow_out, colocate_with_first_write_call=self._colocate_with_first_write_call) ta._infer_shape = self._infer_shape ta._element_shape = self._element_shape ta._colocate_with = self._colocate_with return ta