Clone a functional `Model` instance. Model cloning is similar to calling a model on new inputs, except that it creates new layers (and thus new weights) instead of sharing the weights of the existing layers. Input layers are always cloned. Arguments: model: Instance of `Model`.
(model, input_tensors=None, layer_fn=_clone_layer)
| 126 | |
| 127 | |
| 128 | def _clone_functional_model(model, input_tensors=None, layer_fn=_clone_layer): |
| 129 | """Clone a functional `Model` instance. |
| 130 | |
| 131 | Model cloning is similar to calling a model on new inputs, |
| 132 | except that it creates new layers (and thus new weights) instead |
| 133 | of sharing the weights of the existing layers. |
| 134 | |
| 135 | Input layers are always cloned. |
| 136 | |
| 137 | Arguments: |
| 138 | model: Instance of `Model`. |
| 139 | input_tensors: optional list of input tensors |
| 140 | to build the model upon. If not provided, |
| 141 | placeholders will be created. |
| 142 | layer_fn: callable to be applied on non-input layers in the model. By |
| 143 | default it clones the layer. Another example is to preserve the layer |
| 144 | to share the weights. This is required when we create a per-replica |
| 145 | copy of the model with distribution strategy; we want the weights to |
| 146 | be shared but still feed inputs separately so we create new input |
| 147 | layers. |
| 148 | |
| 149 | Returns: |
| 150 | An instance of `Model` reproducing the behavior |
| 151 | of the original model, on top of new inputs tensors, |
| 152 | using newly instantiated weights. |
| 153 | |
| 154 | Raises: |
| 155 | ValueError: in case of invalid `model` argument value or `layer_fn` |
| 156 | argument value. |
| 157 | """ |
| 158 | if not isinstance(model, Model): |
| 159 | raise ValueError('Expected `model` argument ' |
| 160 | 'to be a `Model` instance, got ', model) |
| 161 | if isinstance(model, Sequential): |
| 162 | raise ValueError('Expected `model` argument ' |
| 163 | 'to be a functional `Model` instance, ' |
| 164 | 'got a `Sequential` instance instead:', model) |
| 165 | if not model._is_graph_network: |
| 166 | raise ValueError('Expected `model` argument ' |
| 167 | 'to be a functional `Model` instance, ' |
| 168 | 'but got a subclass model instead.') |
| 169 | |
| 170 | layer_map = {} # Cache for created layers. |
| 171 | tensor_map = object_identity.ObjectIdentityDictionary( |
| 172 | ) # Map {reference_tensor: corresponding_tensor} |
| 173 | if input_tensors is None: |
| 174 | # Create placeholders to build the model on top of. |
| 175 | input_tensors = [] |
| 176 | for layer in model._input_layers: |
| 177 | input_tensor = Input(**layer.get_config()) |
| 178 | input_tensors.append(input_tensor) |
| 179 | # Cache newly created input layer. |
| 180 | newly_created_input_layer = input_tensor._keras_history.layer |
| 181 | layer_map[layer] = newly_created_input_layer |
| 182 | else: |
| 183 | # Make sure that all input tensors come from a Keras layer. |
| 184 | # If tensor comes from an input layer: cache the input layer. |
| 185 | input_tensors = nest.flatten(input_tensors) |
no test coverage detected