def add(self, layer): """ Adds a layer following all previous layers. Arguments: layer: A layer that supports call, call_inv and log_det. Example: > import invtf > import tensorflow.keras as keras > # Model > g = invtf.Generator() > g.add(invtf.dequantize.UniformDequantize(input_shape=input_shape)) > g.add(invtf.layers.Normalize()) > g.add(invtf.layers.Conv3DCirc()) Comments: This code is essentially that of keras.Sequential [1]. As explained above the class inherits from Model instead of Sequential to allow Multi-Scale architecture with multiple outputs. To simultaneously support the Sequential API we have a modified version of the Sequential 'add(..)' function. The main modification is that the function below allow multiple outputs of MultiScale layers which keras.Sequential does not. TODO: (1) Make InvLayer class everyone inherits from with O(1) mem backprop. """ if len(self._layers) == 0: if not hasattr(layer, "_batch_input_shape"): raise Exception( "The first layer should include input dimension, e.g. UniformDequantize(input_shape=X.shape[1:]). " ) if isinstance(layer, keras.layers.InputLayer): raise Exception( "Don't add an InputLayer, this is the responsibility of the Generator class. " ) if not isinstance(layer, keras.layers.Layer): raise TypeError( "The added layer must be an instance of class Layer. Found: " + str(layer)) self.built = False set_inputs = False from tensorflow.python.keras.engine import input_layer from tensorflow.python.keras.engine import training_utils from tensorflow.python.keras.utils import layer_utils from tensorflow.python.util import nest from tensorflow.python.util import tf_inspect # If list is empty. if not self._layers: batch_shape, dtype = training_utils.get_input_shape_and_dtype( layer) if batch_shape: # Instantiate an input layer. x = input_layer.Input(batch_shape=batch_shape, dtype=dtype, name=layer.name + '_input') # This will build the current layer # and create the node connecting the current layer # to the input layer we just created. layer(x) set_inputs = True if set_inputs: # If an input layer (placeholder) is available. if len(nest.flatten( layer._inbound_nodes[-1].output_tensors)) != 1: raise ValueError( 'All layers of Invertible Generator (besides MultiScale) ' 'should have a single output tensor. ') self.outputs = [ nest.flatten(layer._inbound_nodes[-1].output_tensors)[0] ] self.inputs = layer_utils.get_source_inputs(self.outputs[0]) elif self.outputs: """# If the model is being built continuously on top of an input layer: # refresh its output. output_tensor = layer(self.outputs[0]) # MAIN NEW LINE if isinstance(layer, invtf.layers.MultiScale): output_tensor = output_tensor[0] if len(nest.flatten(output_tensor)) != 1: raise TypeError('All layers of Invertible Gnerator (Besides MultiScale) ' 'should have a single output tensor. ') self.outputs = [output_tensor]""" # If the model is being built continuously on top of an input layer: # refresh its output. output_tensor = layer(self.outputs[0]) # MAIN MODIFICATION. Zs = [] if isinstance(layer, invtf.layers.MultiScale): Zs = [output_tensor[1]] output_tensor = output_tensor[0] if len(nest.flatten(output_tensor)) != 1: raise TypeError( 'All layers of Invertible Generator (Besides MultiScale) ' 'should have a single output tensor. ') self.outputs = [output_tensor] + self.outputs[1:] + Zs if self.outputs: # True if set_inputs or self._is_graph_network or if adding a layer # to an already built deferred seq model. self.built = True if set_inputs or self._is_graph_network: self._init_graph_network(self.inputs, self.outputs, name=self.name) else: self._layers.append(layer) if self._layers: self._track_layers(self._layers) self._layer_call_argspecs[layer] = tf_inspect.getfullargspec( layer.call)
def add(self, layer): """Adds a layer instance on top of the layer stack. Arguments: layer: layer instance. Raises: TypeError: If `layer` is not a layer instance. ValueError: In case the `layer` argument does not know its input shape. ValueError: In case the `layer` argument has multiple output tensors, or is already connected somewhere else (forbidden in `Sequential` models). """ # If we are passed a Keras tensor created by keras.Input(), we can extract # the input layer from its keras history and use that without any loss of # generality. if hasattr(layer, '_keras_history'): origin_layer = layer._keras_history[0] if isinstance(origin_layer, input_layer.InputLayer): layer = origin_layer if not isinstance(layer, base_layer.Layer): raise TypeError('The added layer must be ' 'an instance of class Layer. ' 'Found: ' + str(layer)) tf_utils.assert_no_legacy_layers([layer]) self.built = False set_inputs = False if not self._layers: if isinstance(layer, input_layer.InputLayer): # Corner case where the user passes an InputLayer layer via `add`. assert len( nest.flatten(layer._inbound_nodes[-1].output_tensors)) == 1 set_inputs = True else: batch_shape, dtype = training_utils.get_input_shape_and_dtype( layer) if batch_shape: # Instantiate an input layer. x = input_layer.Input(batch_shape=batch_shape, dtype=dtype, name=layer.name + '_input') # This will build the current layer # and create the node connecting the current layer # to the input layer we just created. layer(x) set_inputs = True if set_inputs: # If an input layer (placeholder) is available. if len(nest.flatten( layer._inbound_nodes[-1].output_tensors)) != 1: raise ValueError('All layers in a Sequential model ' 'should have a single output tensor. ' 'For multi-output layers, ' 'use the functional API.') self.outputs = [ nest.flatten(layer._inbound_nodes[-1].output_tensors)[0] ] self.inputs = layer_utils.get_source_inputs(self.outputs[0]) elif self.outputs: # If the model is being built continuously on top of an input layer: # refresh its output. output_tensor = layer(self.outputs[0]) if len(nest.flatten(output_tensor)) != 1: raise TypeError('All layers in a Sequential model ' 'should have a single output tensor. ' 'For multi-output layers, ' 'use the functional API.') self.outputs = [output_tensor] if set_inputs or self._is_graph_network: self._init_graph_network(self.inputs, self.outputs, name=self.name) self.built = True else: self._layers.append(layer) if self._layers: self._track_layers(self._layers) self._layer_call_argspecs[layer] = tf_inspect.getfullargspec( layer.call)
def add(self, layer): """Adds a layer instance on top of the layer stack. Args: layer: layer instance. Raises: TypeError: If `layer` is not a layer instance. ValueError: In case the `layer` argument does not know its input shape. ValueError: In case the `layer` argument has multiple output tensors, or is already connected somewhere else (forbidden in `Sequential` models). """ # If we are passed a Keras tensor created by keras.Input(), we can extract # the input layer from its keras history and use that without any loss of # generality. if hasattr(layer, '_keras_history'): origin_layer = layer._keras_history[0] if isinstance(origin_layer, input_layer.InputLayer): layer = origin_layer logging.warning( 'Please add `keras.layers.InputLayer` instead of `keras.Input` to ' 'Sequential model. `keras.Input` is intended to be used by ' 'Functional model.') if isinstance(layer, module.Module): if not isinstance(layer, base_layer.Layer): layer = functional.ModuleWrapper(layer) else: raise TypeError('The added layer must be ' 'an instance of class Layer. ' 'Found: ' + str(layer)) tf_utils.assert_no_legacy_layers([layer]) if not self._is_layer_name_unique(layer): raise ValueError('All layers added to a Sequential model ' 'should have unique names. Name "%s" is already the name' ' of a layer in this model. Update the `name` argument ' 'to pass a unique name.' % (layer.name,)) self.built = False set_inputs = False self._maybe_create_attribute('_self_tracked_trackables', []) if not self._self_tracked_trackables: if isinstance(layer, input_layer.InputLayer): # Case where the user passes an Input or InputLayer layer via `add`. set_inputs = True else: batch_shape, dtype = training_utils.get_input_shape_and_dtype(layer) if batch_shape: # Instantiate an input layer. x = input_layer.Input( batch_shape=batch_shape, dtype=dtype, name=layer.name + '_input') # This will build the current layer # and create the node connecting the current layer # to the input layer we just created. layer(x) set_inputs = True if set_inputs: outputs = nest.flatten(layer._inbound_nodes[-1].outputs) if len(outputs) != 1: raise ValueError(SINGLE_LAYER_OUTPUT_ERROR_MSG) self.outputs = outputs self.inputs = layer_utils.get_source_inputs(self.outputs[0]) self.built = True self._has_explicit_input_shape = True elif self.outputs: # If the model is being built continuously on top of an input layer: # refresh its output. output_tensor = layer(self.outputs[0]) if len(nest.flatten(output_tensor)) != 1: raise ValueError(SINGLE_LAYER_OUTPUT_ERROR_MSG) self.outputs = [output_tensor] self.built = True if set_inputs or self._graph_initialized: self._init_graph_network(self.inputs, self.outputs) self._graph_initialized = True else: self._self_tracked_trackables.append(layer) self._handle_deferred_layer_dependencies([layer]) self._layer_call_argspecs[layer] = tf_inspect.getfullargspec(layer.call)
def add(self, layer): """Adds a layer instance on top of the layer stack. Arguments: layer: layer instance. Raises: TypeError: If `layer` is not a layer instance. ValueError: In case the `layer` argument does not know its input shape. ValueError: In case the `layer` argument has multiple output tensors, or is already connected somewhere else (forbidden in `Sequential` models). """ # If we are passed a Keras tensor created by keras.Input(), we can extract # the input layer from its keras history and use that without any loss of # generality. if hasattr(layer, '_keras_history'): origin_layer = layer._keras_history[0] if isinstance(origin_layer, input_layer.InputLayer): layer = origin_layer if not isinstance(layer, base_layer.Layer): raise TypeError('The added layer must be ' 'an instance of class Layer. ' 'Found: ' + str(layer)) tf_utils.assert_no_legacy_layers([layer]) # This allows the added layer to broadcast mutations to the current # layer, which is necessary to ensure cache correctness. layer._attribute_sentinel.add_parent(self._attribute_sentinel) self.built = False set_inputs = False if not self._layers: if isinstance(layer, input_layer.InputLayer): # Corner case where the user passes an InputLayer layer via `add`. assert len( nest.flatten(layer._inbound_nodes[-1].output_tensors)) == 1 set_inputs = True else: batch_shape, dtype = training_utils.get_input_shape_and_dtype( layer) if batch_shape: # Instantiate an input layer. x = input_layer.Input(batch_shape=batch_shape, dtype=dtype, name=layer.name + '_input') # This will build the current layer # and create the node connecting the current layer # to the input layer we just created. layer(x) set_inputs = True if set_inputs: # If an input layer (placeholder) is available. if len(nest.flatten( layer._inbound_nodes[-1].output_tensors)) != 1: raise ValueError(SINGLE_LAYER_OUTPUT_ERROR_MSG) self.outputs = [ nest.flatten(layer._inbound_nodes[-1].output_tensors)[0] ] self.inputs = layer_utils.get_source_inputs(self.outputs[0]) elif self.outputs: # If the model is being built continuously on top of an input layer: # refresh its output. output_tensor = layer(self.outputs[0]) if len(nest.flatten(output_tensor)) != 1: raise ValueError(SINGLE_LAYER_OUTPUT_ERROR_MSG) self.outputs = [output_tensor] if self.outputs: # True if set_inputs or self._is_graph_network or if adding a layer # to an already built deferred seq model. self.built = True if set_inputs or self._is_graph_network: self._init_graph_network(self.inputs, self.outputs, name=self.name) else: self._layers.append(layer) self._handle_deferred_layer_dependencies([layer]) self._layer_call_argspecs[layer] = tf_inspect.getfullargspec( layer.call) # Different Model types add to `._layers` in different ways, so for safety # we do a cache invalidation to make sure the changes are reflected. self._attribute_sentinel.invalidate_all()
def add(self, layer): """Adds a layer instance on top of the layer stack. Arguments: layer: layer instance. Raises: TypeError: If `layer` is not a layer instance. ValueError: In case the `layer` argument does not know its input shape. ValueError: In case the `layer` argument has multiple output tensors, or is already connected somewhere else (forbidden in `Sequential` models). """ # If we are passed a Keras tensor created by keras.Input(), we can extract # the input layer from its keras history and use that without any loss of # generality. if hasattr(layer, '_keras_history'): origin_layer = layer._keras_history[0] if isinstance(origin_layer, input_layer.InputLayer): layer = origin_layer if not isinstance(layer, base_layer.Layer): raise TypeError('The added layer must be ' 'an instance of class Layer. ' 'Found: ' + str(layer)) self.built = False set_inputs = False if not self._layers: if isinstance(layer, input_layer.InputLayer): # Corner case where the user passes an InputLayer layer via `add`. assert len(nest.flatten(layer._inbound_nodes[-1].output_tensors)) == 1 set_inputs = True else: batch_shape, dtype = training_utils.get_input_shape_and_dtype(layer) if batch_shape: # Instantiate an input layer. x = input_layer.Input( batch_shape=batch_shape, dtype=dtype, name=layer.name + '_input') # This will build the current layer # and create the node connecting the current layer # to the input layer we just created. layer(x) set_inputs = True if set_inputs: # If an input layer (placeholder) is available. if len(nest.flatten(layer._inbound_nodes[-1].output_tensors)) != 1: raise ValueError('All layers in a Sequential model ' 'should have a single output tensor. ' 'For multi-output layers, ' 'use the functional API.') self.outputs = [ nest.flatten(layer._inbound_nodes[-1].output_tensors)[0] ] self.inputs = layer_utils.get_source_inputs(self.outputs[0]) elif self.outputs: # If the model is being built continuously on top of an input layer: # refresh its output. output_tensor = layer(self.outputs[0]) if isinstance(output_tensor, list): raise TypeError('All layers in a Sequential model ' 'should have a single output tensor. ' 'For multi-output layers, ' 'use the functional API.') self.outputs = [output_tensor] if set_inputs or self._is_graph_network: self._init_graph_network(self.inputs, self.outputs, name=self.name) self.built = True else: self._layers.append(layer) if self._layers: self._track_layers(self._layers) self._layer_call_argspecs[layer] = tf_inspect.getfullargspec(layer.call)
def add(self, layer): """Adds a layer instance on top of the layer stack. Arguments: layer: layer instance. Raises: TypeError: If `layer` is not a layer instance. ValueError: In case the `layer` argument does not know its input shape. ValueError: In case the `layer` argument has multiple output tensors, or is already connected somewhere else (forbidden in `Sequential` models). """ if not isinstance(layer, base_layer.Layer): raise TypeError('The added layer must be ' 'an instance of class Layer. ' 'Found: ' + str(layer)) self.built = False set_inputs = False if not self._layers: if isinstance(layer, InputLayer): # Corner case where the user passes an InputLayer layer via `add`. assert len(layer._inbound_nodes[-1].output_tensors) == 1 set_inputs = True else: batch_shape, dtype = training_utils.get_input_shape_and_dtype(layer) if batch_shape: # Instantiate an input layer. x = Input( batch_shape=batch_shape, dtype=dtype, name=layer.name + '_input') # This will build the current layer # and create the node connecting the current layer # to the input layer we just created. layer(x) set_inputs = True if set_inputs: # If an input layer (placeholder) is available. if len(layer._inbound_nodes[-1].output_tensors) != 1: raise ValueError('All layers in a Sequential model ' 'should have a single output tensor. ' 'For multi-output layers, ' 'use the functional API.') self.outputs = [layer._inbound_nodes[-1].output_tensors[0]] self.inputs = layer_utils.get_source_inputs(self.outputs[0]) elif self.outputs: # If the model is being built continuously on top of an input layer: # refresh its output. output_tensor = layer(self.outputs[0]) if isinstance(output_tensor, list): raise TypeError('All layers in a Sequential model ' 'should have a single output tensor. ' 'For multi-output layers, ' 'use the functional API.') self.outputs = [output_tensor] if set_inputs or self._is_graph_network: self._init_graph_network(self.inputs, self.outputs, name=self.name) self.built = True else: self._layers.append(layer) if self._layers: self._track_layers(self._layers)
def add(self, layer): from tensorflow.python.keras.utils import tf_utils from tensorflow.python.keras.engine import training_utils from tensorflow.python.util import nest from tensorflow.python.keras.utils import layer_utils from tensorflow.python.util import tf_inspect # If we are passed a Keras tensor created by keras.Input(), we can extract # the input layer from its keras history and use that without any loss of # generality. if hasattr(layer, '_keras_history'): origin_layer = layer._keras_history[0] if isinstance(origin_layer, keras.layers.InputLayer): layer = origin_layer if not isinstance(layer, keras.layers.Layer): raise TypeError('The added layer must be ' 'an instance of class Layer. ' 'Found: ' + str(layer)) tf_utils.assert_no_legacy_layers([layer]) self.built = False set_inputs = False if not self._layers: if isinstance(layer, keras.layers.InputLayer): # Corner case where the user passes an InputLayer layer via `add`. assert len( nest.flatten(layer._inbound_nodes[-1].output_tensors)) == 1 set_inputs = True else: batch_shape, dtype = training_utils.get_input_shape_and_dtype( layer) if batch_shape: # Instantiate an input layer. x = keras.layers.Input(batch_shape=batch_shape, dtype=dtype, name=layer.name + '_input') # This will build the current layer # and create the node connecting the current layer # to the input layer we just created. layer(x) set_inputs = True if set_inputs: # If an input layer (placeholder) is available. if len(nest.flatten( layer._inbound_nodes[-1].output_tensors)) != 1: raise ValueError('All layers in a Sequential model ' 'should have a single output tensor. ' 'For multi-output layers, ' 'use the functional API.') self.outputs = [ nest.flatten(layer._inbound_nodes[-1].output_tensors)[0] ] self.inputs = layer_utils.get_source_inputs(self.outputs[0]) elif self.outputs: # If the model is being built continuously on top of an input layer: # refresh its output. output_tensor = layer(self.outputs[0]) if len(nest.flatten(output_tensor)) != 1 and not isinstance( layer, MultiScale): raise TypeError('All layers in a Sequential model ' 'should have a single output tensor. ' 'For multi-output layers, ' 'use the functional API.') self.outputs = [output_tensor] if self.outputs: # True if set_inputs or self._is_graph_network or if adding a layer # to an already built deferred seq model. self.built = True if set_inputs or self._is_graph_network: self._init_graph_network(self.inputs, self.outputs, name=self.name) else: self._layers.append(layer) if self._layers: self._track_layers(self._layers) self._layer_call_argspecs[layer] = tf_inspect.getfullargspec( layer.call)