• 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"""Home of the `Sequential` model.
17"""
18from __future__ import absolute_import
19from __future__ import division
20from __future__ import print_function
21
22import copy
23
24from tensorflow.python.keras import layers as layer_module
25from tensorflow.python.keras.engine import base_layer
26from tensorflow.python.keras.engine import input_layer
27from tensorflow.python.keras.engine import training
28from tensorflow.python.keras.engine import training_utils
29from tensorflow.python.keras.utils import layer_utils
30from tensorflow.python.platform import tf_logging as logging
31from tensorflow.python.training.tracking import base as trackable
32from tensorflow.python.util import nest
33from tensorflow.python.util import tf_inspect
34from tensorflow.python.util.tf_export import keras_export
35
36
37@keras_export('keras.models.Sequential', 'keras.Sequential')
38class Sequential(training.Model):
39  """Linear stack of layers.
40
41  Arguments:
42      layers: list of layers to add to the model.
43
44  Example:
45
46  ```python
47  # Optionally, the first layer can receive an `input_shape` argument:
48  model = Sequential()
49  model.add(Dense(32, input_shape=(500,)))
50  # Afterwards, we do automatic shape inference:
51  model.add(Dense(32))
52
53  # This is identical to the following:
54  model = Sequential()
55  model.add(Dense(32, input_dim=500))
56
57  # And to the following:
58  model = Sequential()
59  model.add(Dense(32, batch_input_shape=(None, 500)))
60
61  # Note that you can also omit the `input_shape` argument:
62  # In that case the model gets built the first time you call `fit` (or other
63  # training and evaluation methods).
64  model = Sequential()
65  model.add(Dense(32))
66  model.add(Dense(32))
67  model.compile(optimizer=optimizer, loss=loss)
68  # This builds the model for the first time:
69  model.fit(x, y, batch_size=32, epochs=10)
70
71  # Note that when using this delayed-build pattern (no input shape specified),
72  # the model doesn't have any weights until the first call
73  # to a training/evaluation method (since it isn't yet built):
74  model = Sequential()
75  model.add(Dense(32))
76  model.add(Dense(32))
77  model.weights  # returns []
78
79  # Whereas if you specify the input shape, the model gets built continuously
80  # as you are adding layers:
81  model = Sequential()
82  model.add(Dense(32, input_shape=(500,)))
83  model.add(Dense(32))
84  model.weights  # returns list of length 4
85
86  # When using the delayed-build pattern (no input shape specified), you can
87  # choose to manually build your model by calling `build(batch_input_shape)`:
88  model = Sequential()
89  model.add(Dense(32))
90  model.add(Dense(32))
91  model.build((None, 500))
92  model.weights  # returns list of length 4
93  ```
94  """
95
96  @trackable.no_automatic_dependency_tracking
97  def __init__(self, layers=None, name=None):
98    super(Sequential, self).__init__(name=name)
99    self.supports_masking = True
100    self._build_input_shape = None
101    self._compute_output_and_mask_jointly = True
102
103    self._layer_call_argspecs = {}
104
105    # Add to the model any layers passed to the constructor.
106    if layers:
107      for layer in layers:
108        self.add(layer)
109
110  @property
111  def layers(self):
112    # Historically, `sequential.layers` only returns layers that were added
113    # via `add`, and omits the auto-generated `InputLayer` that comes at the
114    # bottom of the stack.
115    # `Trackable` manages the `_layers` attributes and does filtering
116    # over it.
117    layers = super(Sequential, self).layers
118    if layers and isinstance(layers[0], input_layer.InputLayer):
119      return layers[1:]
120    return layers[:]
121
122  @property
123  def dynamic(self):
124    return any(layer.dynamic for layer in self.layers)
125
126  @trackable.no_automatic_dependency_tracking
127  def add(self, layer):
128    """Adds a layer instance on top of the layer stack.
129
130    Arguments:
131        layer: layer instance.
132
133    Raises:
134        TypeError: If `layer` is not a layer instance.
135        ValueError: In case the `layer` argument does not
136            know its input shape.
137        ValueError: In case the `layer` argument has
138            multiple output tensors, or is already connected
139            somewhere else (forbidden in `Sequential` models).
140    """
141    # If we are passed a Keras tensor created by keras.Input(), we can extract
142    # the input layer from its keras history and use that without any loss of
143    # generality.
144    if hasattr(layer, '_keras_history'):
145      origin_layer = layer._keras_history[0]
146      if isinstance(origin_layer, input_layer.InputLayer):
147        layer = origin_layer
148
149    if not isinstance(layer, base_layer.Layer):
150      raise TypeError('The added layer must be '
151                      'an instance of class Layer. '
152                      'Found: ' + str(layer))
153    self.built = False
154    set_inputs = False
155    if not self._layers:
156      if isinstance(layer, input_layer.InputLayer):
157        # Corner case where the user passes an InputLayer layer via `add`.
158        assert len(nest.flatten(layer._inbound_nodes[-1].output_tensors)) == 1
159        set_inputs = True
160      else:
161        batch_shape, dtype = training_utils.get_input_shape_and_dtype(layer)
162        if batch_shape:
163          # Instantiate an input layer.
164          x = input_layer.Input(
165              batch_shape=batch_shape, dtype=dtype, name=layer.name + '_input')
166          # This will build the current layer
167          # and create the node connecting the current layer
168          # to the input layer we just created.
169          layer(x)
170          set_inputs = True
171
172      if set_inputs:
173        # If an input layer (placeholder) is available.
174        if len(nest.flatten(layer._inbound_nodes[-1].output_tensors)) != 1:
175          raise ValueError('All layers in a Sequential model '
176                           'should have a single output tensor. '
177                           'For multi-output layers, '
178                           'use the functional API.')
179        self.outputs = [
180            nest.flatten(layer._inbound_nodes[-1].output_tensors)[0]
181        ]
182        self.inputs = layer_utils.get_source_inputs(self.outputs[0])
183
184    elif self.outputs:
185      # If the model is being built continuously on top of an input layer:
186      # refresh its output.
187      output_tensor = layer(self.outputs[0])
188      if isinstance(output_tensor, list):
189        raise TypeError('All layers in a Sequential model '
190                        'should have a single output tensor. '
191                        'For multi-output layers, '
192                        'use the functional API.')
193      self.outputs = [output_tensor]
194    if set_inputs or self._is_graph_network:
195      self._init_graph_network(self.inputs, self.outputs, name=self.name)
196      self.built = True
197    else:
198      self._layers.append(layer)
199    if self._layers:
200      self._track_layers(self._layers)
201
202    self._layer_call_argspecs[layer] = tf_inspect.getfullargspec(layer.call)
203
204  @trackable.no_automatic_dependency_tracking
205  def pop(self):
206    """Removes the last layer in the model.
207
208    Raises:
209        TypeError: if there are no layers in the model.
210    """
211    if not self.layers:
212      raise TypeError('There are no layers in the model.')
213
214    layer = self._layers.pop()
215    self._layer_call_argspecs.pop(layer)
216    if not self.layers:
217      self.outputs = None
218      self.inputs = None
219      self.built = False
220    elif self._is_graph_network:
221      self.layers[-1]._outbound_nodes = []
222      self.outputs = [self.layers[-1].output]
223      self._init_graph_network(self.inputs, self.outputs, name=self.name)
224      self.built = True
225
226  @base_layer.default
227  def build(self, input_shape=None):
228    if self._is_graph_network:
229      self._init_graph_network(self.inputs, self.outputs, name=self.name)
230    else:
231      if input_shape is None:
232        raise ValueError('You must provide an `input_shape` argument.')
233      input_shape = tuple(input_shape)
234      self._build_input_shape = input_shape
235      super(Sequential, self).build(input_shape)
236    self.built = True
237
238  def call(self, inputs, training=None, mask=None):  # pylint: disable=redefined-outer-name
239    if self._is_graph_network:
240      if not self.built:
241        self._init_graph_network(self.inputs, self.outputs, name=self.name)
242      return super(Sequential, self).call(inputs, training=training, mask=mask)
243
244    outputs = inputs  # handle the corner case where self.layers is empty
245    for layer in self.layers:
246      # During each iteration, `inputs` are the inputs to `layer`, and `outputs`
247      # are the outputs of `layer` applied to `inputs`. At the end of each
248      # iteration `inputs` is set to `outputs` to prepare for the next layer.
249      kwargs = {}
250      argspec = self._layer_call_argspecs[layer].args
251      if 'mask' in argspec:
252        kwargs['mask'] = mask
253      if 'training' in argspec:
254        kwargs['training'] = training
255
256      outputs = layer(inputs, **kwargs)
257
258      # `outputs` will be the inputs to the next layer.
259      inputs = outputs
260      mask = outputs._keras_mask
261
262    return outputs
263
264  def compute_output_shape(self, input_shape):
265    shape = input_shape
266    for layer in self.layers:
267      shape = layer.compute_output_shape(shape)
268    return shape
269
270  def compute_mask(self, inputs, mask):
271    # TODO(omalleyt): b/123540974 This function is not really safe to call
272    # by itself because it will duplicate any updates and losses in graph
273    # mode by `call`ing the Layers again.
274    outputs = self.call(inputs, mask=mask)
275    return outputs._keras_mask
276
277  def predict_proba(self, x, batch_size=32, verbose=0):
278    """Generates class probability predictions for the input samples.
279
280    The input samples are processed batch by batch.
281
282    Arguments:
283        x: input data, as a Numpy array or list of Numpy arrays
284            (if the model has multiple inputs).
285        batch_size: integer.
286        verbose: verbosity mode, 0 or 1.
287
288    Returns:
289        A Numpy array of probability predictions.
290    """
291    preds = self.predict(x, batch_size, verbose)
292    if preds.min() < 0. or preds.max() > 1.:
293      logging.warning('Network returning invalid probability values. '
294                      'The last layer might not normalize predictions '
295                      'into probabilities '
296                      '(like softmax or sigmoid would).')
297    return preds
298
299  def predict_classes(self, x, batch_size=32, verbose=0):
300    """Generate class predictions for the input samples.
301
302    The input samples are processed batch by batch.
303
304    Arguments:
305        x: input data, as a Numpy array or list of Numpy arrays
306            (if the model has multiple inputs).
307        batch_size: integer.
308        verbose: verbosity mode, 0 or 1.
309
310    Returns:
311        A numpy array of class predictions.
312    """
313    proba = self.predict(x, batch_size=batch_size, verbose=verbose)
314    if proba.shape[-1] > 1:
315      return proba.argmax(axis=-1)
316    else:
317      return (proba > 0.5).astype('int32')
318
319  def save(self, filepath, overwrite=True, include_optimizer=True):
320    from tensorflow.python.keras.models import save_model  # pylint: disable=g-import-not-at-top
321    save_model(self, filepath, overwrite, include_optimizer)
322
323  def get_config(self):
324    layer_configs = []
325    for layer in self.layers:
326      layer_configs.append({
327          'class_name': layer.__class__.__name__,
328          'config': layer.get_config()
329      })
330    config = {
331        'name': self.name,
332        'layers': copy.deepcopy(layer_configs)
333    }
334    if self._build_input_shape:
335      config['build_input_shape'] = self._build_input_shape
336    return config
337
338  @classmethod
339  def from_config(cls, config, custom_objects=None):
340    if 'name' in config:
341      name = config['name']
342      build_input_shape = config.get('build_input_shape')
343      layer_configs = config['layers']
344    else:
345      name = None
346      build_input_shape = None
347      layer_configs = config
348    model = cls(name=name)
349    for layer_config in layer_configs:
350      layer = layer_module.deserialize(layer_config,
351                                       custom_objects=custom_objects)
352      model.add(layer)
353    if not model.inputs and build_input_shape:
354      model.build(build_input_shape)
355    if not model._is_graph_network:
356      # Still needs to be built when passed input data.
357      model.built = False
358    return model
359
360  @property
361  def input_spec(self):
362    if self.layers and hasattr(self.layers[0], 'input_spec'):
363      return self.layers[0].input_spec
364    return None
365