Substitute for model cloning that works for subclassed models. Subclassed models cannot be cloned because their topology is not serializable. To "instantiate" an identical model in a new TF graph, we reuse the original model object, but we clear its state. After calling this function on a
(model)
| 411 | |
| 412 | # "Clone" a subclassed model by reseting all of the attributes. |
| 413 | def _in_place_subclassed_model_reset(model): |
| 414 | """Substitute for model cloning that works for subclassed models. |
| 415 | |
| 416 | Subclassed models cannot be cloned because their topology is not serializable. |
| 417 | To "instantiate" an identical model in a new TF graph, we reuse the original |
| 418 | model object, but we clear its state. |
| 419 | |
| 420 | After calling this function on a model instance, you can use the model |
| 421 | instance as if it were a model clone (in particular you can use it in a new |
| 422 | graph). |
| 423 | |
| 424 | This method clears the state of the input model. It is thus destructive. |
| 425 | However the original state can be restored fully by calling |
| 426 | `_in_place_subclassed_model_state_restoration`. |
| 427 | |
| 428 | Args: |
| 429 | model: Instance of a Keras model created via subclassing. |
| 430 | |
| 431 | Raises: |
| 432 | ValueError: In case the model uses a subclassed model as inner layer. |
| 433 | """ |
| 434 | assert not model._is_graph_network # Only makes sense for subclassed networks |
| 435 | # Retrieve all layers tracked by the model as well as their attribute names |
| 436 | attributes_cache = {} |
| 437 | for name in dir(model): |
| 438 | # Skip the check of methods in tf.Module since they basically |
| 439 | # recursively query all the other attributes within same module. |
| 440 | if name == 'submodules': |
| 441 | continue |
| 442 | |
| 443 | try: |
| 444 | value = getattr(model, name) |
| 445 | except (AttributeError, ValueError, TypeError): |
| 446 | continue |
| 447 | if isinstance(value, Layer): |
| 448 | attributes_cache[name] = value |
| 449 | assert value in model.layers |
| 450 | if hasattr(value, 'layers') and value.layers: |
| 451 | raise ValueError('We do not support the use of nested layers ' |
| 452 | 'in `model_to_estimator` at this time. Found nested ' |
| 453 | 'layer: %s' % value) |
| 454 | elif isinstance( |
| 455 | value, (list, tuple)) and name not in ('layers', '_layers', 'metrics', |
| 456 | '_compile_metric_functions', |
| 457 | '_output_loss_metrics'): |
| 458 | # Handle case: list/tuple of layers (also tracked by the Network API). |
| 459 | if value and all(isinstance(val, Layer) for val in value): |
| 460 | raise ValueError('We do not support the use of list-of-layers ' |
| 461 | 'attributes in subclassed models used with ' |
| 462 | '`model_to_estimator` at this time. Found list ' |
| 463 | 'model: %s' % name) |
| 464 | |
| 465 | # Replace layers on the model with fresh layers |
| 466 | layers_to_names = {value: key for key, value in attributes_cache.items()} |
| 467 | original_layers = model._layers[:] |
| 468 | setattr_tracking = model._setattr_tracking |
| 469 | model._setattr_tracking = False |
| 470 | model._layers = [] |
no test coverage detected