def expand_model_by_layer_name(self, new_dimension, layer_name="dense"): """ Expand the current Keras model with provided dimension of the hidden layers or model weights. This method by default expands the dense layer of the current neural network. It can be extends to expand other layers specified by `layer_name`, for example, it can be use to increase the number of CNN filters or increase the hidden layer size inside LSTM. :param new_dimension: New number of dimensions for \ the fully connected layers :type new_dimension: `list` :param layer_name: layer's name to be expanded :type layer_name: `str` :return: None """ if new_dimension is None: raise FLException('No information is provided for ' 'the new expanded model. ' 'Please provide the new dimension of ' 'the resulting expanded model.') model_config = json.loads(self.model.to_json()) i = 0 for layer in model_config['config']['layers']: # find the specified layers if 'class_name' in layer and \ layer['class_name'].strip().lower() == layer_name: layer['config']['units'] = new_dimension[i] i += 1 if self.is_keras: new_model = keras.models.model_from_json(json.dumps(model_config)) else: new_model = tf.keras.models.model_from_json( json.dumps(model_config)) metrics = self.model.metrics_names if 'loss' in metrics: metrics.remove('loss') if not self.use_gpu_for_training or self.num_gpus == 1: new_model.compile(optimizer=self.model.optimizer, loss=self.model.loss, metrics=metrics) elif self.is_keras: from keras.utils import multi_gpu_model new_model = multi_gpu_model(new_model, gpus=self.num_gpus) new_model.compile(optimizer=self.model.optimizer, loss=self.model.loss, metrics=metrics) else: strategy = tf.distribute.MirroredStrategy() with strategy.scope(): new_model.compile(optimizer=self.model.optimizer, loss=self.model.loss, metrics=metrics) self.model = new_model
def get_gradient(self, train_data): """ Compute the gradient with the provided dataset at the current local model's weights. :param train_data: Training data, a tuple \ given in the form (x_train, y_train). :type train_data: `np.ndarray` :return: gradients :rtype: `list` of `np.ndarray` """ with self.graph.as_default(): set_session(self.sess) # set up symbolic variables try: grads = self.model.optimizer.get_gradients( self.model.total_loss, self.model.trainable_weights) except Exception as ex: logger.exception(str(ex)) raise FLException('Error occurred when defining ' 'gradient expression. ') symb_inputs = (self.model._feed_inputs + self.model._feed_targets + self.model._feed_sample_weights) # define the symbolic function if self.is_keras: from keras import backend as k else: from tensorflow.python.keras import backend as k f = k.function(symb_inputs, grads) try: x, y, sample_weight = self.model._standardize_user_data( train_data[0], train_data[1]) except Exception as ex: logger.exception(str(ex)) raise FLException('Error occurred when feeding data samples ' 'to compute current gradient.') return f(x + y + sample_weight)
def get_loss(self, dataset): """ Return the resulting loss computed based on the provided dataset. :param dataset: Provided dataset, a tuple given in the form \ (x_test, y_test) or a datagenerator of type `keras.utils.Sequence`, \ `keras.preprocessing.image.ImageDataGenerator`. :type dataset: `np.ndarray` :return: The resulting loss. :rtype: `float` """ if 'loss' not in self.model.metrics_names: self.model.metrics_names.append('loss') res = self.evaluate(dataset) if 'loss' in res: return res['loss'] else: raise FLException("Loss is not listed in the " "model's metrics_names.")
def load_model(file_name, custom_objects={}): """ Loads a model from disk given the specified file_name :param file_name: Name of the file that contains the model to be loaded. :type file_name: `str` :return: Keras model loaded to memory :rtype: `keras.models.Model` """ # try loading model from keras model = KerasFLModel.load_model_via_keras(file_name, custom_objects) if not model: # try loading model from tf.keras model = KerasFLModel.load_model_via_tf_keras( file_name, custom_objects) if model is None: logger.error('Loading model failed! ' 'An acceptable compiled model should be of type ' '(keras.models/tensorflow.keras.models)!') raise FLException( 'Unable to load the provided compiled model!') return model
def load_model_from_spec(model_spec): """ Loads model from provided model_spec, where model_spec is a `dict` that contains two items: model_spec['model_architecture'] has a pointer to the file where the keras model architecture in stored in json format, and model_spec['model_weights'] contains the path where the associated weights are stored as h5. :return: model :rtype: `keras.models.Model` """ if 'model_definition' in model_spec: model_file = model_spec['model_definition'] model_absolute_path = config.get_absolute_path(model_file) custom_objects = {} if 'custom_objects' in model_spec: custom_objects_config = model_spec['custom_objects'] for custom_object in custom_objects_config: key = custom_object['key'] value = custom_object['value'] path = custom_object['path'] custom_objects[key] = config.get_attr_from_path( path, value) model = KerasFLModel.load_model(model_absolute_path, custom_objects=custom_objects) else: # Load architecture from json file try: model = KerasFLModel.model_from_json_via_keras( model_spec['model_architecture']) if not model: model = KerasFLModel.model_from_json_via_tf_keras( model_spec['model_architecture']) if model is None: logger.error( 'An acceptable compiled model should be of type ' '(keras.models/tensorflow.keras.models)!') raise FLException( 'Unable to load the provided compiled model!') except Exception as ex: logger.error(str(ex)) raise FLException( 'Unable to load the provided compiled model!') # Load weights from h5 file if 'model_weights' in model_spec: model.load_weights(model_spec['model_weights']) # model.load_weights(weights) # Compile model with provided parameters: compiled_option = model_spec['compile_model_options'] try: if 'optimizer' in compiled_option: optimizer = compiled_option['optimizer'] else: logger.warning('No optimizer information was provided ' 'in the compile_model_options, ' 'set keras optimizer to default: SGD') optimizer = 'sgd' if 'loss' in compiled_option: loss = compiled_option['loss'] else: logger.warning('No loss function was provided ' 'in the compile_model_options.' 'set keras loss function to default: None') loss = None if 'metrics' in compiled_option: metrics = compiled_option['metrics'] metrics = [metrics] if isinstance(metrics, str) else metrics else: logger.warning('No metrics information was provided ' 'in the compile_model_options,' 'set keras metrics to default: None') metrics = None model.compile(optimizer=optimizer, loss=loss, metrics=metrics) except Exception as ex: logger.exception(str(ex)) logger.exception('Failed to compiled keras model.') return model