in keras/engine/network.py [0:0]
def _init_graph_network(self, inputs, outputs, name=None, **kwargs):
self._uses_inputs_arg = True
# Normalize and set self.inputs, self.outputs.
self.inputs = to_list(inputs, allow_tuple=True)
self.outputs = to_list(outputs, allow_tuple=True)
# User-provided argument validation.
# Check for redundancy in inputs.
if len(set(self.inputs)) != len(self.inputs):
raise ValueError('The list of inputs passed to the model '
'is redundant. '
'All inputs should only appear once.'
' Found: ' + str(self.inputs))
for x in self.inputs:
# Check that x has appropriate `_keras_history` metadata.
if not hasattr(x, '_keras_history'):
cls_name = self.__class__.__name__
raise ValueError('Input tensors to a ' + cls_name + ' ' +
'must come from `keras.layers.Input`. '
'Received: ' + str(x) +
' (missing previous layer metadata).')
# Check that x is an input tensor.
layer, node_index, tensor_index = x._keras_history
if (len(layer._inbound_nodes) > 1 or
(layer._inbound_nodes and
layer._inbound_nodes[0].inbound_layers)):
cls_name = self.__class__.__name__
warnings.warn(cls_name + ' inputs must come from '
'`keras.layers.Input` '
'(thus holding past layer metadata), '
'they cannot be the output of '
'a previous non-Input layer. '
'Here, a tensor specified as '
'input to your model '
'was not an Input tensor, '
'it was generated by layer ' +
layer.name + '.\n'
'Note that input tensors are '
'instantiated via '
'`tensor = keras.layers.Input(shape)`.\n'
'The tensor that caused the issue was: ' +
str(x.name))
for x in self.outputs:
if not hasattr(x, '_keras_history'):
cls_name = self.__class__.__name__
raise ValueError('Output tensors to a ' + cls_name +
' must be '
'the output of a Keras `Layer` '
'(thus holding past layer metadata). '
'Found: ' + str(x))
self._base_init(name=name, **kwargs)
self._compute_previous_mask = (
has_arg(self.call, 'mask') or
hasattr(self, 'compute_mask'))
# A Network does not create weights of its own,
# thus it is already built.
self.built = True
self._is_graph_network = True
self._input_layers = []
self._output_layers = []
self._input_coordinates = []
self._output_coordinates = []
# This is for performance optimization when calling the Network on new
# inputs. Every time the Network is called on a set on input tensors,
# we compute the output tensors,
# output masks and output shapes in one pass,
# then cache them here. When any of these outputs is queried later, we
# retrieve it from there instead of recomputing it.
self._output_mask_cache = {}
self._output_tensor_cache = {}
self._output_shape_cache = {}
# Build self._output_layers:
for x in self.outputs:
layer, node_index, tensor_index = x._keras_history
self._output_layers.append(layer)
self._output_coordinates.append((layer, node_index, tensor_index))
# Build self._input_layers:
for x in self.inputs:
layer, node_index, tensor_index = x._keras_history
# It's supposed to be an input layer, so only one node
# and one tensor output.
assert node_index == 0
assert tensor_index == 0
self._input_layers.append(layer)
self._input_coordinates.append((layer, node_index, tensor_index))
# Keep track of the network's nodes and layers.
nodes, nodes_by_depth, layers, layers_by_depth = _map_graph_network(
self.inputs, self.outputs)
self._network_nodes = nodes
self._nodes_by_depth = nodes_by_depth
self._layers = layers
self._layers_by_depth = layers_by_depth
# Create the node linking internal inputs to internal outputs.
Node(outbound_layer=self,
inbound_layers=[],
node_indices=[],
tensor_indices=[],
input_tensors=self.inputs,
output_tensors=self.outputs,
# No network-level masking for now.
input_masks=[None for _ in self.inputs],
output_masks=[None for _ in self.outputs],
input_shapes=[x._keras_shape for x in self.inputs],
output_shapes=[x._keras_shape for x in self.outputs])
# Fill in the output mask cache.
masks = []
for x in self.inputs:
layer, node_index, tensor_index = x._keras_history
node = layer._inbound_nodes[node_index]
mask = node.output_masks[tensor_index]
masks.append(mask)
mask_cache_key = object_list_uid(inputs)
mask_cache_key += '_' + object_list_uid(masks)
masks = []
for x in self.outputs:
layer, node_index, tensor_index = x._keras_history
node = layer._inbound_nodes[node_index]
mask = node.output_masks[tensor_index]
masks.append(mask)
mask = unpack_singleton(masks)
self._output_mask_cache[mask_cache_key] = mask
# Build self.input_names and self.output_names.
self.input_names = []
self.output_names = []
self._feed_input_names = []
self._feed_inputs = []
self._feed_input_shapes = []
for i, layer in enumerate(self._input_layers):
# Check that layer is an InputLayer.
if not isinstance(layer, InputLayer):
raise TypeError(
'Input layers to a `Model` must be `InputLayer` objects. '
'Received inputs: {}. '
'Input {} (0-based) originates '
'from layer type `{}`.'.format(inputs,
i,
layer.__class__.__name__))
self.input_names.append(layer.name)
if layer.is_placeholder:
self._feed_inputs.append(layer.input)
self._feed_input_names.append(layer.name)
self._feed_input_shapes.append(self.inputs[i]._keras_shape)
for layer in self._output_layers:
self.output_names.append(layer.name)