def unpack(model, training_config, weights): restored_model = deserialize(model) if training_config is not None: restored_model.compile( **saving_utils.compile_args_from_training_config(training_config)) restored_model.set_weights(weights) return restored_model
def load(path, compile=True): # pylint: disable=redefined-builtin """Loads Keras objects from a SavedModel. Any Keras layer or model saved to the SavedModel will be loaded back as Keras objects. Other objects are loaded as regular trackable objects (same as `tf.saved_model.load`). Currently, Keras saving/loading only retains the Keras object's weights, losses, and call function. The loaded model can be re-compiled, but the original optimizer, compiled loss functions, and metrics are not retained. This is temporary, and `model.save` will soon be able to serialize compiled models. Args: path: Path to SavedModel. compile: If true, compile the model after loading it. Returns: Object loaded from SavedModel. """ # TODO(kathywu): Add saving/loading of optimizer, compiled losses and metrics. # TODO(kathywu): Add code to load from objects that contain all endpoints model = tf_load.load_internal(path, loader_cls=KerasObjectLoader) if isinstance(model, RevivedModel) and compile: # TODO(kathywu): Use compiled objects from SavedModel, instead of # creating new objects from the training config. if model._training_config is not None: # pylint: disable=protected-access model.compile(**saving_utils.compile_args_from_training_config( model._training_config)) # pylint: disable=protected-access return model
def load(self, compile_model: bool = False, custom_objects: Optional[dict] = None) -> Model: """ Loads a Tensorflow model from a TileDB array. :param compile_model: Boolean. Whether to compile the model after loading or not. :param custom_objects: Optional dictionary mapping names (strings) to custom classes or functions to be considered during deserialization. :return: Model. Tensorflow model. """ model_array = tiledb.open(self.uri) model_array_results = model_array[:] model_weights = pickle.loads( model_array_results["model_weights"].item(0)) model_config = json.loads(model_array.meta["model_config"]) architecture = model_config["config"] model_class = model_config["class_name"] if model_class == "Sequential": model = tf.keras.Sequential.from_config(architecture) elif model_class == "Functional": model = tf.keras.Model.from_config(architecture) else: raise NotImplementedError( "No support for Subclassed models at the moment. Your " "model should be either Sequential or Functional.") model.set_weights(model_weights) if compile_model: optimizer_weights = pickle.loads( model_array_results["optimizer_weights"].item(0)) training_config = json.loads(model_array.meta["training_config"]) # Compile model. model.compile(**saving_utils.compile_args_from_training_config( training_config, custom_objects)) saving_utils.try_build_compiled_arguments(model) # Set optimizer weights. if optimizer_weights: try: model.optimizer._create_all_weights( model.trainable_variables) except (NotImplementedError, AttributeError): logging.warning( "Error when creating the weights of optimizer {}, making it " "impossible to restore the saved optimizer state. As a result, " "your model is starting with a freshly initialized optimizer." ) try: model.optimizer.set_weights(optimizer_weights) except ValueError: logging.warning("Error in loading the saved optimizer " "state. As a result, your model is " "starting with a freshly initialized " "optimizer.") return model
def unpack(model, training_config, weights): """Make Keras Model exportable within pipeline ("picklable") 1/2""" restored_model = deserialize(model) if training_config is not None: restored_model.compile( **saving_utils.compile_args_from_training_config(training_config)) restored_model.set_weights(weights) return restored_model
def load(path, compile=True, options=None): # pylint: disable=redefined-builtin """Loads Keras objects from a SavedModel. Any Keras layer or model saved to the SavedModel will be loaded back as Keras objects. Other objects are loaded as regular trackable objects (same as `tf.saved_model.load`). Currently, Keras saving/loading only retains the Keras object's weights, losses, and call function. The loaded model can be re-compiled, but the original optimizer, compiled loss functions, and metrics are not retained. This is temporary, and `model.save` will soon be able to serialize compiled models. Args: path: Path to SavedModel. compile: If true, compile the model after loading it. options: Optional `tf.saved_model.LoadOptions` object that specifies options for loading from SavedModel. Returns: Object loaded from SavedModel. """ # TODO(kathywu): Add saving/loading of optimizer, compiled losses and metrics. # TODO(kathywu): Add code to load from objects that contain all endpoints model = tf_load.load_internal(path, options=options, loader_cls=KerasObjectLoader) # pylint: disable=protected-access if isinstance(model, training_lib.Model) and compile: # TODO(kathywu): Use compiled objects from SavedModel, instead of # creating new objects from the training config. training_config = model._serialized_attributes['metadata'].get( 'training_config', None) if training_config is not None: model.compile(**saving_utils.compile_args_from_training_config( training_config)) saving_utils.try_build_compiled_arguments(model) else: logging.warning( 'No training configuration found in save file, so the ' 'model was *not* compiled. Compile it manually.') # pylint: enable=protected-access # Force variables and resources to initialize. if not context.executing_eagerly(): sess = backend.get_session() # Variables are initialized by this call. sess.run(ops.get_collection(ops.GraphKeys.TABLE_INITIALIZERS)) return model
def unpack_keras_model(model, training_config, weights): """Creates a new Keras model object using the input parameters. Returns ------- Model A copy of the input Keras Model, compiled if the original was compiled. """ restored_model = deserialize_layer(model) if training_config is not None: restored_model.compile( **saving_utils.compile_args_from_training_config(training_config)) restored_model.set_weights(weights) restored_model.__reduce_ex__ = pack_keras_model.__get__(restored_model) return restored_model
def _unpack_obj(obj): """Recursively unpacks objects. """ if isinstance(obj, SavedKerasModel): restored_model = deserialize(obj.model) training_config = obj.training_config restored_model.compile( **saving_utils.compile_args_from_training_config( training_config)) restored_model.set_weights(obj.weights) return restored_model if hasattr(obj, "__dict__"): for key, val in obj.__dict__.items(): obj.__dict__[key] = _unpack_obj(val) return obj if isinstance(obj, (list, tuple)): obj_type = type(obj) new_obj = obj_type([_unpack_obj(o) for o in obj]) return new_obj return obj # not much we can do at this point, cross fingers
def _clone_prebuilt_model(build_fn): """Clones and compiles a pre-built model when build_fn is an existing Keras model instance. Arguments: build_fn : instance of Keras Model. Returns: copy of the input model with no training. """ model = clone_model(build_fn) # clone_model does not compy over compilation parameters, do those manually model_metadata = saving_utils.model_metadata(build_fn) if "training_config" in model_metadata: training_config = model_metadata["training_config"] else: raise ValueError("To use %s as `build_fn`, you must compile" "it first." % build_fn) model.compile( **saving_utils.compile_args_from_training_config(training_config)) return model
def load(path, compile=True, options=None): # pylint: disable=redefined-builtin """Loads Keras objects from a SavedModel. Any Keras layer or model saved to the SavedModel will be loaded back as Keras objects. Other objects are loaded as regular trackable objects (same as `tf.saved_model.load`). Currently, Keras saving/loading only retains the Keras object's weights, losses, and call function. The loaded model can be re-compiled, but the original optimizer, compiled loss functions, and metrics are not retained. This is temporary, and `model.save` will soon be able to serialize compiled models. Args: path: Path to SavedModel. compile: If true, compile the model after loading it. options: Optional `tf.saved_model.LoadOptions` object that specifies options for loading from SavedModel. Returns: Object loaded from SavedModel. """ # TODO(kathywu): Add saving/loading of optimizer, compiled losses and metrics. # TODO(kathywu): Add code to load from objects that contain all endpoints # Look for metadata file or parse the SavedModel metadata = saved_metadata_pb2.SavedMetadata() meta_graph_def = loader_impl.parse_saved_model(path).meta_graphs[0] object_graph_def = meta_graph_def.object_graph_def path_to_metadata_pb = os.path.join(path, constants.SAVED_METADATA_PATH) if gfile.Exists(path_to_metadata_pb): try: with gfile.GFile(path_to_metadata_pb, 'rb') as f: file_content = f.read() metadata.ParseFromString(file_content) except message.DecodeError as e: raise IOError('Cannot parse keras metadata {}: {}.' .format(path_to_metadata_pb, str(e))) else: logging.warning('SavedModel saved prior to TF 2.4 detected when loading ' 'Keras model. Please ensure that you are saving the model ' 'with model.save() or tf.keras.models.save_model(), *NOT* ' 'tf.saved_model.save(). To confirm, there should be a file ' 'named "keras_metadata.pb" in the SavedModel directory.') _read_legacy_metadata(object_graph_def, metadata) if not metadata.nodes: # When there are no Keras objects, return the results from the core loader return tf_load.load(path, options=options) # Recreate layers and metrics using the info stored in the metadata. keras_loader = KerasObjectLoader(metadata, object_graph_def) keras_loader.load_layers(compile=compile) # Generate a dictionary of all loaded nodes. nodes_to_load = {'root': None} for node_id, loaded_node in keras_loader.loaded_nodes.items(): nodes_to_load[keras_loader.get_path(node_id)] = loaded_node loaded = tf_load.load_partial(path, nodes_to_load, options=options) # Finalize the loaded layers and remove the extra tracked dependencies. keras_loader.finalize_objects() keras_loader.del_tracking() model = loaded['root'] # pylint: disable=protected-access if isinstance(model, training_lib.Model) and compile: # TODO(kathywu): Use compiled objects from SavedModel, instead of # creating new objects from the training config. training_config = model._serialized_attributes['metadata'].get( 'training_config', None) if training_config is not None: model.compile(**saving_utils.compile_args_from_training_config( training_config)) saving_utils.try_build_compiled_arguments(model) else: logging.warning('No training configuration found in save file, so the ' 'model was *not* compiled. Compile it manually.') # pylint: enable=protected-access # Force variables and resources to initialize. if not context.executing_eagerly(): sess = backend.get_session() # Variables are initialized by this call. sess.run(ops.get_collection(ops.GraphKeys.TABLE_INITIALIZERS)) return model
def load_model_from_hdf5(filepath, custom_objects=None, compile=True): # pylint: disable=redefined-builtin """Loads a model saved via `save_model_to_hdf5`. Arguments: filepath: One of the following: - String, path to the saved model - `h5py.File` object from which to load the model custom_objects: Optional dictionary mapping names (strings) to custom classes or functions to be considered during deserialization. compile: Boolean, whether to compile the model after loading. Returns: A Keras model instance. If an optimizer was found as part of the saved model, the model is already compiled. Otherwise, the model is uncompiled and a warning will be displayed. When `compile` is set to False, the compilation is omitted without any warning. Raises: ImportError: if h5py is not available. ValueError: In case of an invalid savefile. """ if h5py is None: raise ImportError('`load_model` requires h5py.') if not custom_objects: custom_objects = {} opened_new_file = not isinstance(filepath, h5py.File) if opened_new_file: f = h5py.File(filepath, mode='r') else: f = filepath model = None try: # instantiate model model_config = f.attrs.get('model_config') if model_config is None: raise ValueError('No model found in config file.') model_config = json.loads(model_config.decode('utf-8')) model = model_config_lib.model_from_config( model_config, custom_objects=custom_objects) # set weights load_weights_from_hdf5_group(f['model_weights'], model.layers) if compile: # instantiate optimizer training_config = f.attrs.get('training_config') if training_config is None: logging.warning( 'No training configuration found in save file: ' 'the model was *not* compiled. Compile it manually.') return model training_config = json.loads(training_config.decode('utf-8')) # Compile model. model.compile(**saving_utils.compile_args_from_training_config( training_config, custom_objects)) # Set optimizer weights. if 'optimizer_weights' in f: # Build train function (to get weight updates). # Models that aren't graph networks must wait until they are called # with data to _make_train_function() and so can't load optimizer # weights. if model._is_graph_network: # pylint: disable=protected-access model._make_train_function() optimizer_weight_values = load_optimizer_weights_from_hdf5_group( f) try: model.optimizer.set_weights(optimizer_weight_values) except ValueError: logging.warning('Error in loading the saved optimizer ' 'state. As a result, your model is ' 'starting with a freshly initialized ' 'optimizer.') else: logging.warning( 'Sequential models without an `input_shape` ' 'passed to the first layer cannot reload their ' 'optimizer state. As a result, your model is' 'starting with a freshly initialized optimizer.') finally: if opened_new_file: f.close() return model
def load_model_from_hdf5(filepath, custom_objects=None, compile=True): # pylint: disable=redefined-builtin """Loads a model saved via `save_model_to_hdf5`. Arguments: filepath: One of the following: - String, path to the saved model - `h5py.File` object from which to load the model custom_objects: Optional dictionary mapping names (strings) to custom classes or functions to be considered during deserialization. compile: Boolean, whether to compile the model after loading. Returns: A Keras model instance. If an optimizer was found as part of the saved model, the model is already compiled. Otherwise, the model is uncompiled and a warning will be displayed. When `compile` is set to False, the compilation is omitted without any warning. Raises: ImportError: if h5py is not available. ValueError: In case of an invalid savefile. """ if h5py is None: raise ImportError('`load_model` requires h5py.') if not custom_objects: custom_objects = {} opened_new_file = not isinstance(filepath, h5py.File) if opened_new_file: f = h5py.File(filepath, mode='r') else: f = filepath model = None try: # instantiate model model_config = f.attrs.get('model_config') if model_config is None: raise ValueError('No model found in config file.') model_config = json.loads(model_config.decode('utf-8')) model = model_config_lib.model_from_config(model_config, custom_objects=custom_objects) # set weights load_weights_from_hdf5_group(f['model_weights'], model.layers) if compile: # instantiate optimizer training_config = f.attrs.get('training_config') if training_config is None: logging.warning('No training configuration found in the save file, so ' 'the model was *not* compiled. Compile it manually.') return model training_config = json.loads(training_config.decode('utf-8')) # Compile model. model.compile(**saving_utils.compile_args_from_training_config( training_config, custom_objects)) # Set optimizer weights. if 'optimizer_weights' in f: try: model.optimizer._create_all_weights(model.trainable_variables) except (NotImplementedError, AttributeError): logging.warning( 'Error when creating the weights of optimizer {}, making it ' 'impossible to restore the saved optimizer state. As a result, ' 'your model is starting with a freshly initialized optimizer.') optimizer_weight_values = load_optimizer_weights_from_hdf5_group(f) try: model.optimizer.set_weights(optimizer_weight_values) except ValueError: logging.warning('Error in loading the saved optimizer ' 'state. As a result, your model is ' 'starting with a freshly initialized ' 'optimizer.') finally: if opened_new_file: f.close() return model
def load(path, compile=True, options=None): # pylint: disable=redefined-builtin """Loads Keras objects from a SavedModel. Any Keras layer or model saved to the SavedModel will be loaded back as Keras objects. Other objects are loaded as regular trackable objects (same as `tf.saved_model.load`). Currently, Keras saving/loading only retains the Keras object's weights, losses, and call function. The loaded model can be re-compiled, but the original optimizer, compiled loss functions, and metrics are not retained. This is temporary, and `model.save` will soon be able to serialize compiled models. Args: path: Path to SavedModel. compile: If true, compile the model after loading it. options: Optional `tf.saved_model.LoadOptions` object that specifies options for loading from SavedModel. Returns: Object loaded from SavedModel. """ # TODO(kathywu): Add saving/loading of optimizer, compiled losses and metrics. # TODO(kathywu): Add code to load from objects that contain all endpoints # The Keras metadata file is not yet saved, so create it from the SavedModel. metadata = saved_metadata_pb2.SavedMetadata() meta_graph_def = loader_impl.parse_saved_model(path).meta_graphs[0] object_graph_def = meta_graph_def.object_graph_def # TODO(kathywu): When the keras metadata file is saved, load it directly # instead of calling the _read_legacy_metadata function. _read_legacy_metadata(object_graph_def, metadata) if not metadata.nodes: # When there are no Keras objects, return the results from the core loader return tf_load.load(path, options=options) # Recreate layers and metrics using the info stored in the metadata. keras_loader = KerasObjectLoader(metadata, object_graph_def) keras_loader.load_layers(compile=compile) # Generate a dictionary of all loaded nodes. nodes_to_load = {'root': None} for node_id, loaded_node in keras_loader.loaded_nodes.items(): nodes_to_load[keras_loader.get_path(node_id)] = loaded_node loaded = tf_load.load_partial(path, nodes_to_load, options=options) # Finalize the loaded layers and remove the extra tracked dependencies. keras_loader.finalize_objects() keras_loader.del_tracking() model = loaded['root'] # pylint: disable=protected-access if isinstance(model, training_lib.Model) and compile: # TODO(kathywu): Use compiled objects from SavedModel, instead of # creating new objects from the training config. training_config = model._serialized_attributes['metadata'].get( 'training_config', None) if training_config is not None: model.compile(**saving_utils.compile_args_from_training_config( training_config)) saving_utils.try_build_compiled_arguments(model) else: logging.warning('No training configuration found in save file, so the ' 'model was *not* compiled. Compile it manually.') # pylint: enable=protected-access # Force variables and resources to initialize. if not context.executing_eagerly(): sess = backend.get_session() # Variables are initialized by this call. sess.run(ops.get_collection(ops.GraphKeys.TABLE_INITIALIZERS)) return model
# import tensorflow as tf from tensorflow.python.keras.saving.saved_model.load import KerasObjectLoader from tensorflow.python.saved_model.load import load_internal from tensorflow.python.keras.saving.saved_model.load import RevivedModel from tensorflow.python.keras.saving import saving_utils from tensorflow.python.saved_model import loader_impl model_path = 'output/saved_model/cls/1599723701' loader_impl.parse_saved_model(model_path) model = load_internal(model_path, tags=['serve'], loader_cls=KerasObjectLoader) if not isinstance(model, RevivedModel): raise RuntimeError("Can not load model") if model._training_config is None: raise RuntimeError("Model _training_config is None") model.compile( **saving_utils.compile_args_from_training_config(model._training_config)) test_data = [[], [], [], []] model.predict(test_data)
def load( self, *, timestamp: Optional[Timestamp] = None, compile_model: bool = False, custom_objects: Optional[Mapping[str, Any]] = None, input_shape: Optional[Tuple[int, ...]] = None, ) -> tf.keras.Model: """ Load a Tensorflow model from a TileDB array. :param timestamp: Range of timestamps to load fragments of the array which live in the specified time range. :param compile_model: Whether to compile the model after loading or not. :param custom_objects: Mapping of names to custom classes or functions to be considered during deserialization. :param input_shape: The shape that the custom model expects as input :return: Tensorflow model. """ # TODO: Change timestamp when issue in core is resolved with tiledb.open(self.uri, ctx=self.ctx, timestamp=timestamp) as model_array: model_array_results = model_array[:] model_config = json.loads(model_array.meta["model_config"]) model_class = model_config["class_name"] if model_class != "Sequential" and model_class != "Functional": with generic_utils.SharedObjectLoadingScope(): with generic_utils.CustomObjectScope(custom_objects or {}): if hasattr(model_config, "decode"): model_config = model_config.decode("utf-8") model = model_config_lib.model_from_config( model_config, custom_objects=custom_objects) if not model.built: model.build(input_shape) # Load weights for layers self._load_custom_subclassed_model(model, model_array) else: cls = (tf.keras.Sequential if model_class == "Sequential" else tf.keras.Model) model = cls.from_config(model_config["config"]) model_weights = pickle.loads( model_array_results["model_weights"].item(0)) model.set_weights(model_weights) if compile_model: optimizer_weights = pickle.loads( model_array_results["optimizer_weights"].item(0)) training_config = json.loads( model_array.meta["training_config"]) # Compile model. model.compile(**saving_utils.compile_args_from_training_config( training_config, custom_objects)) saving_utils.try_build_compiled_arguments(model) # Set optimizer weights. if optimizer_weights: try: model.optimizer._create_all_weights( model.trainable_variables) except (NotImplementedError, AttributeError): logging.warning( "Error when creating the weights of optimizer {}, making it " "impossible to restore the saved optimizer state. As a result, " "your model is starting with a freshly initialized optimizer." ) try: model.optimizer.set_weights(optimizer_weights) except ValueError: logging.warning("Error in loading the saved optimizer " "state. As a result, your model is " "starting with a freshly initialized " "optimizer.") return model