• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ==============================================================================
15# pylint: disable=protected-access
16"""Input layer code (`Input` and `InputLayer`)."""
17
18from tensorflow.python.distribute import distribution_strategy_context
19from tensorflow.python.framework import ops
20from tensorflow.python.framework import tensor_shape
21from tensorflow.python.framework import tensor_spec
22from tensorflow.python.keras import backend
23from tensorflow.python.keras.distribute import distributed_training_utils
24from tensorflow.python.keras.engine import base_layer
25from tensorflow.python.keras.engine import keras_tensor
26from tensorflow.python.keras.engine import node as node_module
27from tensorflow.python.keras.saving.saved_model import layer_serialization
28from tensorflow.python.keras.utils import tf_utils
29from tensorflow.python.util.tf_export import keras_export
30
31
32def _assert_other_arg_none(arg_name, arg):
33  if arg is not None:
34    raise ValueError('When `type_spec` is not None, all other args '
35                     'except `name` must be None, '
36                     'but %s is not None.' % arg_name)
37
38
39@keras_export('keras.layers.InputLayer')
40class InputLayer(base_layer.Layer):
41  """Layer to be used as an entry point into a Network (a graph of layers).
42
43  It can either wrap an existing tensor (pass an `input_tensor` argument)
44  or create a placeholder tensor (pass arguments `input_shape`, and
45  optionally, `dtype`).
46
47  It is generally recommend to use the functional layer API via `Input`,
48  (which creates an `InputLayer`) without directly using `InputLayer`.
49
50  When using InputLayer with Keras Sequential model, it can be skipped by
51  moving the input_shape parameter to the first layer after the InputLayer.
52
53  This class can create placeholders for tf.Tensors, tf.SparseTensors, and
54  tf.RaggedTensors by choosing 'sparse=True' or 'ragged=True'. Note that
55  'sparse' and 'ragged' can't be configured to True at same time.
56  Usage:
57
58  ```python
59  # With explicit InputLayer.
60  model = tf.keras.Sequential([
61    tf.keras.layers.InputLayer(input_shape=(4,)),
62    tf.keras.layers.Dense(8)])
63  model.compile(tf.optimizers.RMSprop(0.001), loss='mse')
64  model.fit(np.zeros((10, 4)),
65            np.ones((10, 8)))
66
67  # Without InputLayer and let the first layer to have the input_shape.
68  # Keras will add a input for the model behind the scene.
69  model = tf.keras.Sequential([
70    tf.keras.layers.Dense(8, input_shape=(4,))])
71  model.compile(tf.optimizers.RMSprop(0.001), loss='mse')
72  model.fit(np.zeros((10, 4)),
73            np.ones((10, 8)))
74  ```
75
76  Args:
77      input_shape: Shape tuple (not including the batch axis), or `TensorShape`
78        instance (not including the batch axis).
79      batch_size: Optional input batch size (integer or None).
80      dtype: Optional datatype of the input. When not provided, the Keras
81          default float type will be used.
82      input_tensor: Optional tensor to use as layer input. If set, the layer
83          will use the `tf.TypeSpec` of this tensor rather
84          than creating a new placeholder tensor.
85      sparse: Boolean, whether the placeholder created is meant to be sparse.
86          Default to False.
87      ragged: Boolean, whether the placeholder created is meant to be ragged.
88          In this case, values of 'None' in the 'shape' argument represent
89          ragged dimensions. For more information about RaggedTensors, see
90          [this guide](https://www.tensorflow.org/guide/ragged_tensors).
91          Default to False.
92      type_spec: A `tf.TypeSpec` object to create Input from. This `tf.TypeSpec`
93          represents the entire batch. When provided, all other args except
94          name must be None.
95      name: Optional name of the layer (string).
96  """
97
98  def __init__(self,
99               input_shape=None,
100               batch_size=None,
101               dtype=None,
102               input_tensor=None,
103               sparse=None,
104               name=None,
105               ragged=None,
106               type_spec=None,
107               **kwargs):
108    self._init_input_shape = input_shape
109    self._init_batch_size = batch_size
110    self._init_dtype = dtype
111    self._init_sparse = sparse
112    self._init_ragged = ragged
113    self._init_type_spec = type_spec
114
115    strategy = distribution_strategy_context.get_strategy()
116    if strategy and batch_size is not None and \
117        distributed_training_utils.global_batch_size_supported(strategy):
118      if batch_size % strategy.num_replicas_in_sync != 0:
119        raise ValueError('The `batch_size` argument ({}) must be divisible by '
120                         'the number of replicas ({})'.format(
121                             batch_size, strategy.num_replicas_in_sync))
122      batch_size = batch_size // strategy.num_replicas_in_sync
123
124    if 'batch_input_shape' in kwargs:
125      batch_input_shape = kwargs.pop('batch_input_shape')
126      if input_shape and batch_input_shape:
127        raise ValueError('Only provide the input_shape OR '
128                         'batch_input_shape argument to '
129                         'InputLayer, not both at the same time.')
130      # Set the input shape and batch size from the batch_input_shape.
131      # Note that batch_input_shape can be None (unknown rank) or [] (scalar),
132      # in which case the batch size must be None.
133      if batch_input_shape:
134        batch_size = batch_input_shape[0]
135        input_shape = batch_input_shape[1:]
136    if kwargs:
137      raise ValueError('Unrecognized keyword arguments:', kwargs.keys())
138
139    if sparse and ragged:
140      raise ValueError(
141          'Cannot set both sparse and ragged to True in a Keras input.')
142
143    if not name:
144      prefix = 'input'
145      name = prefix + '_' + str(backend.get_uid(prefix))
146
147    if not dtype:
148      if input_tensor is None:
149        dtype = backend.floatx()
150      else:
151        dtype = backend.dtype(input_tensor)
152    elif input_tensor is not None and input_tensor.dtype != dtype:
153      raise ValueError('`input_tensor.dtype` differs from `dtype`: %s vs. %s' %
154                       (input_tensor.dtype, dtype))
155    super(InputLayer, self).__init__(dtype=dtype, name=name)
156    self.built = True
157    self.sparse = True if sparse else False
158    self.ragged = True if ragged else False
159    self.batch_size = batch_size
160    self.supports_masking = True
161
162    if isinstance(input_shape, tensor_shape.TensorShape):
163      input_shape = tuple(input_shape.as_list())
164    elif isinstance(input_shape, int):
165      input_shape = (input_shape,)
166
167    if type_spec is not None:
168      args_that_must_be_none = [
169          ('(input_)shape', self._init_input_shape),
170          ('batch_size', self._init_batch_size),
171          ('dtype', self._init_dtype),
172          ('input_tensor', input_tensor),
173          ('sparse', self._init_sparse),
174          ('ragged', self._init_ragged),
175      ]
176      for arg_name, arg in args_that_must_be_none:
177        _assert_other_arg_none(arg_name, arg)
178      if not ops.executing_eagerly_outside_functions():
179        raise ValueError('Creating Keras inputs from a type_spec is only '
180                         'supported when eager execution is enabled.')
181      input_tensor = keras_tensor.keras_tensor_from_type_spec(type_spec)
182      if isinstance(input_tensor, keras_tensor.SparseKerasTensor):
183        self.sparse = True
184      if isinstance(input_tensor, keras_tensor.RaggedKerasTensor):
185        self.ragged = True
186      self.is_placeholder = True
187      try:
188        self._batch_input_shape = tuple(input_tensor.shape.as_list())
189      except ValueError:
190        # If the shape cannot be represented as a tuple (e.g. unknown rank)
191        self._batch_input_shape = None
192    elif input_tensor is None:
193      if input_shape is not None:
194        batch_input_shape = (batch_size,) + tuple(input_shape)
195      else:
196        batch_input_shape = None
197      graph = backend.get_graph()
198      with graph.as_default():
199        input_tensor = backend.placeholder(
200            shape=batch_input_shape,
201            dtype=dtype,
202            name=self.name,
203            sparse=sparse,
204            ragged=ragged)
205
206      self.is_placeholder = True
207      self._batch_input_shape = batch_input_shape
208    else:
209      if ops.executing_eagerly_outside_functions():
210        if not isinstance(input_tensor, keras_tensor.KerasTensor):
211          input_tensor = keras_tensor.keras_tensor_from_tensor(input_tensor)
212      else:
213        if not tf_utils.is_symbolic_tensor(input_tensor):
214          raise ValueError('You should not pass an EagerTensor to `Input`. '
215                           'For example, instead of creating an '
216                           'InputLayer, you should instantiate your model and '
217                           'directly call it on your input.')
218      self.is_placeholder = False
219      try:
220        self._batch_input_shape = tuple(input_tensor.shape.as_list())
221      except ValueError:
222        # If the shape cannot be represented as a tuple (e.g. unknown rank)
223        self._batch_input_shape = None
224    # Create an input node.
225    input_tensor._keras_mask = None
226    node_module.Node(layer=self, outputs=input_tensor)
227
228    # Store type spec
229    if isinstance(input_tensor, keras_tensor.KerasTensor) or (
230        tf_utils.is_extension_type(input_tensor)):
231      self._type_spec = input_tensor._type_spec  # pylint: disable=protected-access
232    else:
233      self._type_spec = tensor_spec.TensorSpec(
234          shape=input_tensor.shape, dtype=input_tensor.dtype, name=self.name)
235
236  def get_config(self):
237    if self._init_type_spec is not None:
238      config = {
239          'name': self.name,
240          'type_spec': self._init_type_spec
241      }
242    else:
243      config = {
244          'batch_input_shape': self._batch_input_shape,
245          'dtype': self.dtype,
246          'sparse': self.sparse,
247          'ragged': self.ragged,
248          'name': self.name,
249      }
250    return config
251
252  @property
253  def _trackable_saved_model_saver(self):
254    return layer_serialization.InputLayerSavedModelSaver(self)
255
256
257@keras_export('keras.Input', 'keras.layers.Input')
258def Input(  # pylint: disable=invalid-name
259    shape=None,
260    batch_size=None,
261    name=None,
262    dtype=None,
263    sparse=None,
264    tensor=None,
265    ragged=None,
266    type_spec=None,
267    **kwargs):
268  """`Input()` is used to instantiate a Keras tensor.
269
270  A Keras tensor is a symbolic tensor-like object,
271  which we augment with certain attributes that allow us to build a Keras model
272  just by knowing the inputs and outputs of the model.
273
274  For instance, if `a`, `b` and `c` are Keras tensors,
275  it becomes possible to do:
276  `model = Model(input=[a, b], output=c)`
277
278  Args:
279      shape: A shape tuple (integers), not including the batch size.
280          For instance, `shape=(32,)` indicates that the expected input
281          will be batches of 32-dimensional vectors. Elements of this tuple
282          can be None; 'None' elements represent dimensions where the shape is
283          not known.
284      batch_size: optional static batch size (integer).
285      name: An optional name string for the layer.
286          Should be unique in a model (do not reuse the same name twice).
287          It will be autogenerated if it isn't provided.
288      dtype: The data type expected by the input, as a string
289          (`float32`, `float64`, `int32`...)
290      sparse: A boolean specifying whether the placeholder to be created is
291          sparse. Only one of 'ragged' and 'sparse' can be True. Note that,
292          if `sparse` is False, sparse tensors can still be passed into the
293          input - they will be densified with a default value of 0.
294      tensor: Optional existing tensor to wrap into the `Input` layer.
295          If set, the layer will use the `tf.TypeSpec` of this tensor rather
296          than creating a new placeholder tensor.
297      ragged: A boolean specifying whether the placeholder to be created is
298          ragged. Only one of 'ragged' and 'sparse' can be True. In this case,
299          values of 'None' in the 'shape' argument represent ragged dimensions.
300          For more information about RaggedTensors, see
301          [this guide](https://www.tensorflow.org/guide/ragged_tensors).
302      type_spec: A `tf.TypeSpec` object to create the input placeholder from.
303          When provided, all other args except name must be None.
304      **kwargs: deprecated arguments support. Supports `batch_shape` and
305          `batch_input_shape`.
306
307  Returns:
308    A `tensor`.
309
310  Example:
311
312  ```python
313  # this is a logistic regression in Keras
314  x = Input(shape=(32,))
315  y = Dense(16, activation='softmax')(x)
316  model = Model(x, y)
317  ```
318
319  Note that even if eager execution is enabled,
320  `Input` produces a symbolic tensor-like object (i.e. a placeholder).
321  This symbolic tensor-like object can be used with lower-level
322  TensorFlow ops that take tensors as inputs, as such:
323
324  ```python
325  x = Input(shape=(32,))
326  y = tf.square(x)  # This op will be treated like a layer
327  model = Model(x, y)
328  ```
329
330  (This behavior does not work for higher-order TensorFlow APIs such as
331  control flow and being directly watched by a `tf.GradientTape`).
332
333  However, the resulting model will not track any variables that were
334  used as inputs to TensorFlow ops. All variable usages must happen within
335  Keras layers to make sure they will be tracked by the model's weights.
336
337  The Keras Input can also create a placeholder from an arbitrary `tf.TypeSpec`,
338  e.g:
339
340  ```python
341  x = Input(type_spec=tf.RaggedTensorSpec(shape=[None, None],
342                                          dtype=tf.float32, ragged_rank=1))
343  y = x.values
344  model = Model(x, y)
345  ```
346  When passing an arbitrary `tf.TypeSpec`, it must represent the signature of an
347  entire batch instead of just one example.
348
349  Raises:
350    ValueError: If both `sparse` and `ragged` are provided.
351    ValueError: If both `shape` and (`batch_input_shape` or `batch_shape`) are
352      provided.
353    ValueError: If `shape`, `tensor` and `type_spec` are None.
354    ValueError: If arguments besides `type_spec` are non-None while `type_spec`
355                is passed.
356    ValueError: if any unrecognized parameters are provided.
357  """
358  if sparse and ragged:
359    raise ValueError(
360        'Cannot set both sparse and ragged to True in a Keras input.')
361
362  input_layer_config = {'name': name, 'dtype': dtype, 'sparse': sparse,
363                        'ragged': ragged, 'input_tensor': tensor,
364                        'type_spec': type_spec}
365
366  batch_input_shape = kwargs.pop('batch_input_shape',
367                                 kwargs.pop('batch_shape', None))
368  if shape is not None and batch_input_shape is not None:
369    raise ValueError('Only provide the `shape` OR `batch_input_shape` argument '
370                     'to Input, not both at the same time.')
371  if (batch_input_shape is None and shape is None and tensor is None
372      and type_spec is None):
373    raise ValueError('Please provide to Input a `shape`'
374                     ' or a `tensor` or a `type_spec` argument. Note that '
375                     '`shape` does not include the batch '
376                     'dimension.')
377  if kwargs:
378    raise ValueError('Unrecognized keyword arguments:', kwargs.keys())
379
380  if batch_input_shape:
381    shape = batch_input_shape[1:]
382    input_layer_config.update({'batch_input_shape': batch_input_shape})
383  else:
384    input_layer_config.update(
385        {'batch_size': batch_size, 'input_shape': shape})
386  input_layer = InputLayer(**input_layer_config)
387
388  # Return tensor including `_keras_history`.
389  # Note that in this case train_output and test_output are the same pointer.
390  outputs = input_layer._inbound_nodes[0].outputs
391  if isinstance(outputs, list) and len(outputs) == 1:
392    return outputs[0]
393  else:
394    return outputs
395