def apply_transformations(in_model): src_model = None src_model_config = in_model.get_config() k = 1024 for info_txt, check_func, apply_func in zip(info_list[:k], check_transform_list[:k], apply_transform_list[:k]): if check_func(src_model_config): if src_model is None: print('Preparation for the transformation...\n') src_model = Model.from_config(in_model.get_config(), custom_objects=extra_custom_objects) transfer_weights(in_model, src_model, {}) check_transform(in_model, src_model) print(info_txt) src_model_config = src_model.get_config() dst_model_config, weight_transfer_rule_dict = apply_func(src_model_config) dst_model = Model.from_config(dst_model_config, custom_objects=extra_custom_objects) transfer_weights(src_model, dst_model, weight_transfer_rule_dict) check_transform(in_model, dst_model) del src_model src_model = dst_model else: print(f'Nothing to do with {info_txt.split(":")[0]} transform\n') if src_model is None: return in_model return src_model
def create_dropout_predict_function(model, dropout): """ Hard-codes a dropout rate to the Dropout layers of a trained model. When initially training model, Dropout layers must have training=True, otherwise dropout will not be applied to predictions. Parameters: model : trained keras model dropout : dropout rate to apply to all Dropout layers Returns: predict_with_dropout : keras model that will apply dropout when making predictions """ # Load the config of the original model conf = model.get_config() # Add the specified dropout to all layers for layer in conf['layers']: # Dropout layers if layer["class_name"]=="Dropout": layer["config"]["rate"] = dropout # Recurrent layers with dropout elif "dropout" in layer["config"].keys(): layer["config"]["dropout"] = dropout # Create a new model with specified dropout if type(model)==Sequential: # Sequential model_dropout = Sequential.from_config(conf) else: # Functional model_dropout = Model.from_config(conf) model_dropout.set_weights(model.get_weights()) return model_dropout
def from_config(cls, config, custom_objects={}): if type(custom_objects) is list: custom_objects = {obj.__name__: obj for obj in custom_objects} custom_objects.update(_get_cells()) model_config = config.pop('model_config') model = Model.from_config(model_config, custom_objects) return cls(model, **config)
def split(model, start, end): confs = model.get_config() kept_layers = set() for i, l in enumerate(confs['layers']): if i == 0: confs['layers'][0]['config']['batch_input_shape'] = model.layers[ start].input_shape if i != start: # confs['layers'][0]['name'] += str(random.randint(0, 100000000)) confs['layers'][0]['config']['name'] = confs['layers'][0][ 'name'] elif i < start or i > end: continue kept_layers.add(l['name']) # filter layers layers = [l for l in confs['layers'] if l['name'] in kept_layers] layers[1]['inbound_nodes'][0][0][0] = layers[0]['name'] # set conf confs['layers'] = layers confs['input_layers'][0][0] = layers[0]['name'] confs['output_layers'][0][0] = layers[-1]['name'] # create new model submodel = Model.from_config(confs) for l in submodel.layers: orig_l = model.get_layer(l.name) if orig_l is not None: l.set_weights(orig_l.get_weights()) return submodel
def adapt_keras_model(keras_model, model_name): keras_model_config = keras_model.get_config() keras_model_config['name'] = model_name # assert len(keras_model_config['input_layers']) == len( # keras_model_config['output_layers']) == 1, 'Multi IN/OUT is not supported' if len(keras_model_config['output_layers']) != 1: print("WARNING :: Multi Output Detected!!!") if is_multi_output(keras_model_config): adapted_model_config = split_output_nodes(keras_model_config) # adapted_model_config = rename_layer(adapted_model_config, keras_model_config['input_layers'][0][0], 'data') # adapted_model_config = rename_layer(adapted_model_config, keras_model_config['output_layers'][0][0], 'output') adapted_keras_model = Model.from_config( adapted_model_config, custom_objects=extra_custom_objects) else: adapted_keras_model = Model.from_config( keras_model_config, custom_objects=extra_custom_objects) adapted_keras_model.set_weights(keras_model.get_weights()) return adapted_keras_model
def make_predictions(model, weights, test_gen, lr): config = model.get_config() pmodel = Model.from_config(config) # copy of the model pmodel.set_weights( weights) #load saved weights with lowest validation loss pmodel.compile(Adam(lr=lr), loss='categorical_crossentropy', metrics=['accuracy']) print( 'Training has completed. Now loading test set to see how accurate the model is' ) results = pmodel.evaluate(test_gen, verbose=0) print('Model accuracy on Test Set is {0:7.2f} %'.format(results[1] * 100)) predictions = pmodel.predict(test_gen, verbose=0) return predictions
def deepspam_load(path="model"): global wordmap global model print('Loading Model...') config=json.load(open(path+"/model.config","rt")) model = Model.from_config(config) model.load_weights(path+"/model.weights") ####weights=pickle.load(open("model.weights", "rb")) #model.set_weights(weights) try: wordmap=pickle.load(open(path+"/model.wordmap-py3", "rb")) except: wordmap=pickle.load(open(path+"/model.wordmap-py2", "rb")) #wordmap=[] print("MODEL loaded! (%d words)"%(len(wordmap))) return wordmap
def reset_pingpong(self): """ Reset the models for pingpong training """ logger.debug("Resetting models") # Clear models and graph self.predictors = dict() K.clear_session() # Load Models for current training run for model in self.networks.values(): model.network = Model.from_config(model.config) model.network.set_weights(model.weights) inputs = self.get_inputs() self.build_autoencoders(inputs) self.compile_predictors(initialize=False) logger.debug("Reset models")
def deepspam_load(path="model"): global wordmap global model # global tf_session # print('Creating TF session...') # config = tensorflow.ConfigProto( # intra_op_parallelism_threads=1, # allow_soft_placement=True # ) # tf_session = tensorflow.Session(config=config) # tensorflow.set_session(tf_session) global tf_session global tf_graph print('Loading Model...') config = json.load(open(path + "/model.config", "rt")) model = Model.from_config(config) model.load_weights(path + "/model.weights") ####weights=pickle.load(open("model.weights", "rb")) #model.set_weights(weights) try: wordmap = pickle.load(open(path + "/model.wordmap-py3", "rb")) except: wordmap = pickle.load(open(path + "/model.wordmap-py2", "rb")) #wordmap=[] print("MODEL loaded! (%d words)" % (len(wordmap))) # testing data = np.zeros((1, MAX_SEQUENCE_LENGTH), dtype='int32') classes = model.predict(data, batch_size=1, verbose=1) tf_session = K.get_session() tf_graph = tensorflow.get_default_graph() tf_graph.finalize() print("MODEL finalized!") return wordmap
def from_config(cls, config, custom_objects={}): if type(custom_objects) is list: custom_objects = {obj.__name__: obj for obj in custom_objects} custom_objects.update(_get_cells()) config = config.copy() model_config = config.pop('model_config') if model_config is None: model = None else: model = Model.from_config(model_config, custom_objects) if type(model.input) is list: input = model.input[0] initial_states = model.input[1:] else: input = model.input initial_states = None if type(model.output) is list: output = model.output[0] final_states = model.output[1:] else: output = model.output final_states = None return cls(input, output, initial_states, final_states, **config)
def deepspam_worker(q, path): print('Loading Model...') config = json.load(open(path + "/model.config", "rt")) model = Model.from_config(config) model.load_weights(path + "/model.weights") ####weights=pickle.load(open("model.weights", "rb")) #model.set_weights(weights) #wordmap=[] # print("MODEL loaded! (%d words)"%(len(wordmap))) print("worker: started!!!") while True: dprint("worker: waiting for job... (%d)" % (q.qsize())) data, retq = q.get() if not retq: break dprint("worker: new job!") classes = model.predict(data, batch_size=1, verbose=1) res = classes[0][0] * 100.0 / (classes[0][0] + classes[0][1]) dprint("worker: result=" + str(res)) retq.put(res) q.task_done() print("worker: exiting!!!") q.task_done()
# ============================================================== # optimizer = tf.keras.optimizers.Adam(lr=LEARNING_RATE) optimizer = tf.keras.mixed_precision.experimental.LossScaleOptimizer( opt=optimizer, loss_scale=loss_scaler) print('Optimizer Configuration:') print('\nOptimizer `get_slot_names()`: %s\n' % str(optimizer.get_slot_names())) autoencoder = Model(inputs, decoded) autoencoder.compile(optimizer=optimizer, loss='mae', metrics=['mae']) # ============ Test Model Recreation from config ============ # model_config = autoencoder.get_config() autoencoder = Model.from_config(model_config) autoencoder.compile(optimizer=optimizer, loss='mae', metrics=['mae'], run_eagerly=False) # ============ Test Model Summary ============ # autoencoder.summary() from callback import ProgbarLogger progbar_callback = ProgbarLogger(count_mode='samples', stateful_metrics=['mae']) print("\nEvaluation Before training - At Initialization") autoencoder.evaluate(x=df_eval_conv,
def _createMobilenetv2Backbone(self, output_stride=16): mobilenetv2 = MobileNetV2(weights='imagenet', input_shape=(self.dl_input_shape[1], self.dl_input_shape[2], 3), include_top=False) mobile_config = mobilenetv2.get_config() mobile_weights = mobilenetv2.get_weights() #tf.keras.backend.clear_session() assert output_stride in [ 8, 16 ], "Only suported output_stride= 8 o 16 for backbone mobilenetv2." dilatation = 1 for layer in mobile_config['layers']: if layer['name'] == 'input_1': layer['config']['batch_input_shape'] = ( None, self.dl_input_shape[-3], self.dl_input_shape[-2], self.dl_input_shape[-1]) self.logger.info(layer['name'] + ', ' + str(layer['config']['batch_input_shape'])) if output_stride == 8: if layer['name'] == 'block_6_depthwise': layer['config']['strides'] = (1, 1) dilatation = dilatation * 2 #Replace stride for dilatation self.logger.info(layer['name'] + ', strides=' + str(layer['config']['strides']) + ', ' + str(layer['config']['dilation_rate'])) if layer['name'] == 'block_7_depthwise': layer['config']['dilation_rate'] = (dilatation, dilatation) self.logger.info(layer['name'] + ', ' + str(layer['config']['strides']) + ', ' + str(layer['config']['dilation_rate'])) if layer['name'] == 'block_8_depthwise': layer['config']['dilation_rate'] = (dilatation, dilatation) self.logger.info(layer['name'] + ', ' + str(layer['config']['strides']) + ', ' + str(layer['config']['dilation_rate'])) if layer['name'] == 'block_9_depthwise': layer['config']['dilation_rate'] = (dilatation, dilatation) self.logger.info(layer['name'] + ', ' + str(layer['config']['strides']) + ', ' + str(layer['config']['dilation_rate'])) if layer['name'] == 'block_10_depthwise': layer['config']['dilation_rate'] = (dilatation, dilatation) self.logger.info(layer['name'] + ', ' + str(layer['config']['strides']) + ', ' + str(layer['config']['dilation_rate'])) if layer['name'] == 'block_11_depthwise': layer['config']['dilation_rate'] = (dilatation, dilatation) self.logger.info(layer['name'] + ', ' + str(layer['config']['strides']) + ', ' + str(layer['config']['dilation_rate'])) if layer['name'] == 'block_12_depthwise': layer['config']['dilation_rate'] = (dilatation, dilatation) self.logger.info(layer['name'] + ', ' + str(layer['config']['strides']) + ', ' + str(layer['config']['dilation_rate'])) if output_stride in [8, 16]: if layer['name'] == 'block_13_depthwise': layer['config']['strides'] = (1, 1) dilatation = dilatation * 2 #Replace stride for dilatation self.logger.info(layer['name'] + ', ' + str(layer['config']['strides']) + ', ' + str(layer['config']['dilation_rate'])) if layer['name'] == 'block_14_depthwise': layer['config']['dilation_rate'] = (dilatation, dilatation) self.logger.info(layer['name'] + ', ' + str(layer['config']['strides']) + ', ' + str(layer['config']['dilation_rate'])) if layer['name'] == 'block_15_depthwise': layer['config']['dilation_rate'] = (dilatation, dilatation) self.logger.info(layer['name'] + ', ' + str(layer['config']['strides']) + ', ' + str(layer['config']['dilation_rate'])) if layer['name'] == 'block_16_depthwise': layer['config']['dilation_rate'] = (dilatation, dilatation) self.logger.info(layer['name'] + ', ' + str(layer['config']['strides']) + ', ' + str(layer['config']['dilation_rate'])) # tf.keras.backend.clear_session() new_mobilenetv2 = Model.from_config(mobile_config) mobile_weights[0] = np.resize(mobile_weights[0], [3, 3, self.dl_input_shape[-1], 32]) new_mobilenetv2.set_weights(mobile_weights) self.backbone = Model( inputs=new_mobilenetv2.inputs, outputs=new_mobilenetv2.get_layer('block_16_project_BN').output) self.strideOutput32LayerName = 'block_16_project_BN' self.strideOutput16LayerName = 'block_12_add' self.strideOutput8LayerName = 'block_5_add' self.inputLayerName = mobilenetv2.layers[0].name
def __build_sample_model(self, batch_input_length) -> dict: """ Model that predicts a single OHE character. This model is generated from the modified config file of the self.batch_model. Returns: The dictionary of the configuration. """ self.__batch_input_length = batch_input_length # Get the configuration of the batch_model config = self.model.get_config() # Keep only the "Decoder_Inputs" as single input to the sample_model config["input_layers"] = [config["input_layers"][0]] # Find decoder states that are used as inputs in batch_model and remove them idx_list = [] for idx, layer in enumerate(config["layers"]): if "Decoder_State_" in layer["name"]: idx_list.append(idx) # Pop the layer from the layer list # Revert indices to avoid re-arranging after deleting elements for idx in sorted(idx_list, reverse=True): config["layers"].pop(idx) # Remove inbound_nodes dependencies of remaining layers on deleted ones for layer in config["layers"]: idx_list = [] try: for idx, inbound_node in enumerate(layer["inbound_nodes"][0]): if "Decoder_State_" in inbound_node[0]: idx_list.append(idx) # Catch the exception for first layer (Decoder_Inputs) that has empty list of inbound_nodes[0] except: pass # Pop the inbound_nodes from the list # Revert indices to avoid re-arranging for idx in sorted(idx_list, reverse=True): layer["inbound_nodes"][0].pop(idx) # Change the batch_shape of input layer config["layers"][0]["config"]["batch_input_shape"] = ( batch_input_length, 1, self.dec_input_shape[-1], ) # Finally, change the statefulness of the RNN layers for layer in config["layers"]: if "Decoder_LSTM_" in layer["name"]: layer["config"]["stateful"] = True # layer["config"]["return_sequences"] = True # Define the sample_model using the modified config file sample_model = Model.from_config(config) # Copy the trained weights from the trained batch_model to the untrained sample_model for layer in sample_model.layers: # Get weights from the batch_model weights = self.model.get_layer(layer.name).get_weights() # Set the weights to the sample_model sample_model.get_layer(layer.name).set_weights(weights) if batch_input_length == 1: self.__sample_model = sample_model elif batch_input_length > 1: self.__multi_sample_model = sample_model return config
def _createVGG16Backbone(self, output_stride=16): vgg16 = VGG16(weights='imagenet', input_shape=(self.dl_input_shape[1], self.dl_input_shape[2], 3), include_top=False) assert output_stride in [ 8, 16 ], "Only suported output_stride= 8 o 16 for backbone vgg16." mobile_config = vgg16.get_config() mobile_weights = vgg16.get_weights() #tf.keras.backend.clear_session() dilatation = 1 stride_enable = False for layer in mobile_config['layers']: if layer['name'] == 'input_1': layer['config']['batch_input_shape'] = ( None, self.dl_input_shape[-3], self.dl_input_shape[-2], self.dl_input_shape[-1]) self.logger.info(layer['name'] + ', ' + str(layer['config']['batch_input_shape'])) if output_stride == 8: if layer['name'] == 'block4_pool': layer['config']['strides'] = (1, 1) layer['config']['pool_size'] = (1, 1) dilatation = dilatation * 2 #Replace stride for dilatation self.logger.info(layer['name'] + ', strides=' + str(layer['config']['strides']) + ', ' + str(layer['config']['pool_size'])) stride_enable = True if output_stride in [8, 16]: if layer['name'] == 'block5_pool': layer['config']['strides'] = (1, 1) layer['config']['pool_size'] = (1, 1) dilatation = dilatation * 2 #Replace stride for dilatation self.logger.info(layer['name'] + ', ' + str(layer['config']['strides']) + ', ' + str(layer['config']['pool_size'])) stride_enable = True if 'conv' in layer['name'] and stride_enable: layer['config']['dilation_rate'] = (dilatation, dilatation) self.logger.info(layer['name'] + ', ' + str(layer['config']['strides']) + ', ' + str(layer['config']['dilation_rate'])) new_vgg16 = Model.from_config(mobile_config) mobile_weights[0] = np.resize(mobile_weights[0], [ mobile_weights[0].shape[0], mobile_weights[0].shape[1], self.dl_input_shape[-1], mobile_weights[0].shape[-1] ]) #update input to suport 4 channels new_vgg16.set_weights(mobile_weights) x = new_vgg16.output x = Conv2D(filters=512, kernel_size=3, name='block_6_conv1', padding="same", dilation_rate=dilatation, activation='relu')(x) x = Conv2D(filters=512, kernel_size=3, name='block_6_conv2', padding="same", dilation_rate=dilatation, activation='relu')(x) x = Conv2D(filters=512, kernel_size=3, name='block_6_conv3', padding="same", dilation_rate=dilatation, activation='relu')(x) self.backbone = Model(inputs=new_vgg16.inputs, outputs=x) self.strideOutput32LayerName = 'block6_conv3' self.strideOutput16LayerName = 'block5_conv3' self.strideOutput8LayerName = 'block4_conv3' self.inputLayerName = vgg16.layers[0].name
def convert(prevmodel, export_path, export_name): graph1 = tf.Graph() with graph1.as_default(): sess1 = tf.Session() with sess1.as_default(): previous_model = load_model(prevmodel) previous_model.summary() config = previous_model.get_config() weights = previous_model.get_weights() graph2 = tf.Graph() with graph2.as_default(): sess2 = tf.Session() with sess2.as_default(): K.set_learning_phase(0) try: model = Sequential.from_config(config) except: model = Model.from_config(config) model.set_weights(weights) with open( os.path.join(export_path, export_name + '.input_output.txt'), 'w') as fid: model_input_name = model.input.name #model_input_node_name model_output_name = model.output.name print(f"Input name: {model_input_name}") print(f"Output name: {model_output_name}") fid.write(f"{model_input_name}\n") fid.write(f"{model_output_name}\n") model_output_node_name = model.output.name.split(':')[0] graph_file = os.path.join(export_path, export_name + ".graph.pbtxt") ckpt_file = os.path.join(export_path, export_name + ".ckpt") saver = tf.train.Saver() tf.train.write_graph(sess2.graph_def, '', graph_file) save_path = saver.save(sess2, ckpt_file) # freeze the graph frozen_graph_def = tf.graph_util.convert_variables_to_constants( sess2, # The session is used to retrieve the weights graph2.as_graph_def( ), # The graph_def is used to retrieve the nodes model_output_node_name.split( "," ) # The output node names are used to select the usefull nodes ) # Finally we serialize and dump the output graph to the filesystem frozen_graph_path = os.path.join(export_path, export_name + ".frozen.pb") with tf.gfile.GFile(frozen_graph_path, "wb") as f: f.write(frozen_graph_def.SerializeToString()) #tf.reset_default_graph() #frozen_graph_def = freeze_graph(export_path, model_output_node_name) tf.reset_default_graph() train_writer = tf.summary.FileWriter(export_path) train_writer.add_graph(frozen_graph_def) train_writer.flush() # optimize for inference optimized_graph_def = optimize_for_inference_lib.optimize_for_inference( frozen_graph_def, [model_input_name.split(':')[0]], [model_output_name.split(':')[0]], tf.float32.as_datatype_enum) #tf.int32.as_datatype_enum optimized_graph_path = os.path.join( export_path, export_name + ".optimized_for_inference.pb") with tf.gfile.GFile(optimized_graph_path, "wb") as f: f.write(optimized_graph_def.SerializeToString()) # tflite # ## from frozen graph converter = tflite.TocoConverter.from_frozen_graph( optimized_graph_path, [model_input_name.split(':')[0]], [model_output_name.split(':')[0]], {model_input_name.split(':')[0]: [1, 32, 32, 3]}) # ## from keras model file # only available in tensorflow >=1.11 #converter = tflite.TocoConverter.from_keras_model_file(prevmodel) converter.post_training_quantize = True #converter.inference_type = tf.quint8 #converter.inference_input_type = tf.float32 tflite_quantized_model = converter.convert() optimized_graph_path = os.path.join(export_path, export_name + ".tflite") open(optimized_graph_path, "wb").write(tflite_quantized_model)
def _createResnetBackbone(self, output_stride=16, depth='101'): resnet101 = ResNet101(weights='imagenet', input_shape=(self.dl_input_shape[1], self.dl_input_shape[2], 3), include_top=False) assert output_stride in [ 8, 16 ], "Only suported output_stride= 8 o 16 for backbone resnet." resnet101_config = resnet101.get_config() resnet101_weights = resnet101.get_weights() #tf.keras.backend.clear_session() output_stride = 8 dilatation = 1 stride_enable = False for layer in resnet101_config['layers']: if layer['name'] == 'input_1': layer['config']['batch_input_shape'] = ( None, self.dl_input_shape[-3], self.dl_input_shape[-2], self.dl_input_shape[-1]) self.logger.info(layer['name'] + ', ' + str(layer['config']['batch_input_shape'])) if output_stride == 8 and (layer['name'] == 'conv4_block1_1_conv' or layer['name'] == 'conv4_block1_0_conv'): layer['config']['strides'] = (1, 1) self.logger.info(layer['name'] + ', strides=' + str(layer['config']['strides']) + ', ' + str(layer['config']['dilation_rate'])) stride_enable = True if layer['name'] == 'conv4_block1_1_conv': dilatation = dilatation * 2 #Replace stride for dilatation elif output_stride in [8, 16]: if layer['name'] == 'conv5_block1_1_conv' or layer[ 'name'] == 'conv5_block1_0_conv': self.logger.info(layer['name'] + ', ' + str(layer['config']['strides']) + ', ' + str(layer['config']['dilation_rate'])) layer['config']['strides'] = (1, 1) self.logger.info(layer['name'] + ', ' + str(layer['config']['strides']) + ', ' + str(layer['config']['dilation_rate'])) stride_enable = True if layer['name'] == 'conv5_block1_1_conv': dilatation = dilatation * 2 #Replace stride for dilatation elif stride_enable and ('_conv' in layer['name']): if layer['config']['kernel_size'] != (1, 1): layer['config']['dilation_rate'] = (dilatation, dilatation) self.logger.info(layer['name'] + ', ' + str(layer['config']['strides']) + ', ' + str(layer['config']['dilation_rate'])) else: self.logger.info(layer['name'] + ', ' + str(layer['config']['strides']) + ', ' + str(layer['config']['dilation_rate'])) self.backbone = Model.from_config(resnet101_config) resnet101_weights[0] = np.resize(resnet101_weights[0], [ resnet101_weights[0].shape[0], resnet101_weights[0].shape[1], self.dl_input_shape[-1], resnet101_weights[0].shape[-1] ]) #update input to suport 4 channels self.backbone.set_weights(resnet101_weights) self.strideOutput32LayerName = 'conv5_block3_out' self.strideOutput16LayerName = 'conv4_block23_out' self.strideOutput8LayerName = 'conv3_block4_out' self.inputLayerName = resnet101.layers[0].name
def partial_trainability(model_keras, Layer_names, Layer_trainabliities): """ This function allows you to get partially trainable layers function takes model_keras: keras model you have loaded or created for example using model_zoo.get_model("VGG_small_4",32,3,2) Layer_names: list containing the names of the layers that should be changed. Of course these names have to be existing in model_keras Layer_trainability: list containing floats. For each layer that should be changed, provide a value between 0 and 1 (0-layer not trainable at all; 1-layer entirely trainable) Lets say you use Layer_names=['dense_3'] and Layer_trainability=[0.25] Lets assume 'dense_3' has 1000 nodes. Then two new parallell dense layers will be created. The first one gets 750 nodes, which are set to set to Trainable=False. The second dense layer has 250 nodes, which are trainable. The corresponding weights from the initial model are distributed to these layer accordingly. """ #Get the config of the current model model_config = model_keras.get_config() #Deep-Copy the config of the original model model_config_new = copy.deepcopy(model_config) if type(model_config_new) == dict: print("Model used functional API of Keras") elif type(model_config_new) == list: print( "Model used sequential API of Keras and will now be converted to functional API" ) #api = "Sequential" #Convert to functional API input_layer = Input(batch_shape=model_keras.layers[0].input_shape) prev_layer = input_layer for layer in model_keras.layers: prev_layer = layer(prev_layer) model_keras = Model([input_layer], [prev_layer]) #Now we have functional API :) #Get the model config for the converted model model_config = model_keras.get_config() model_config_new = copy.deepcopy(model_config) else: print("Unknown format for model config") #return Layer_nontrainability = list(1 - np.array(Layer_trainabliities)) del Layer_trainabliities #Original names of the layers Layer_names_orig = [ model_keras.layers[i].name for i in range(len(model_keras.layers)) ] #Now we are starting to loop over all the requested changes: for i in range(len(Layer_names)): nontrainability = Layer_nontrainability[i] layer_name = Layer_names[i] layer_names_list = [ model_config_new["layers"][it]['name'] for it in range(len(model_config_new["layers"])) ] layer_index = int( np.where(np.array(layer_names_list) == layer_name)[0]) layer_config = model_config_new['layers'][layer_index] layer_type = layer_config["class_name"] if layer_type == "Dense": split_property = "units" #'units' are the number of nodes in dense layers elif layer_type == "Conv2D": split_property = "filters" nr_nodes = layer_config["config"][split_property] nr_const = int(np.round(nontrainability * nr_nodes)) #get a config for the non-trainable part layer_config_const = copy.deepcopy(layer_config) layer_name_const = layer_config_const['config']["name"] + "_1" layer_config_const["config"][split_property] = nr_const layer_config_const["config"]["trainable"] = False #not trainable layer_config_const["config"]["name"] = layer_name_const #rename layer_config_const["name"] = layer_name_const #rename #get a config for the rest (trainable part) layer_config_rest = copy.deepcopy(layer_config) #this part will only exist if nr_nodes-nr_const>0: if nr_nodes - nr_const > 0: layer_name_rest = layer_config_rest["config"]["name"] + "_2" layer_config_rest["config"][split_property] = nr_nodes - nr_const layer_config_rest["config"]["name"] = layer_name_rest #rename layer_config_rest["name"] = layer_name_rest #rename #Assemble a config for a corresponding concatenate layer inbound_1 = [layer_name_const, 0, 0, {}] inbound_2 = [layer_name_rest, 0, 0, {}] inbound_nodes = [inbound_1, inbound_2] layer_name = layer_config['config'][ "name"] #Call it like the initial layer that has been there. This will allow other layers to correctly conncet like before #'concatenate_'+layer_config["config"]["name"] config_conc = {"axis": -1, "name": layer_name, "trainable": True} conc_dict = { "class_name": 'Concatenate', "config": config_conc, "inbound_nodes": [inbound_nodes], "name": layer_name } #insert these layers into the config at Index: layer_index layerlist = model_config_new["layers"] #Replace existing layer with the const part layerlist[layer_index] = layer_config_const #After that insert the rest part layerlist.insert(layer_index + 1, layer_config_rest) #After that insert the concatenate layer layerlist.insert(layer_index + 2, conc_dict) #Update the config with the new layers model_config_new["layers"] = layerlist #Build the model using this updated config model_keras_new = Model.from_config(model_config_new) #Compilation might not be required. model_keras_new.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) iterator = 0 for layer_name in Layer_names_orig: #for all layers of the original model layer = model_keras.get_layer(layer_name) if layer_name not in Layer_names: #if this layer was not subjected to change in the new model... #Straight forward: get weights of the orignal model weights = layer.get_weights() #And put them into the new model model_keras_new.get_layer(layer_name).set_weights(weights) else: #Otherwise the layer was changed layer_type = layer.__class__.__name__ layer_config = layer.get_config() weights = layer.get_weights() #Get the original weights trainability = Layer_nontrainability[iterator] iterator += 1 if layer_type == "Dense": split_property = "units" #'units' are the number of nodes in dense layers elif layer_type == "Conv2D": split_property = "filters" nr_nodes = layer_config[split_property] nr_const = int(np.round(trainability * nr_nodes)) #Constant part if layer_type == "Dense": #Put the former weights into the layer weights_const = list(np.copy(weights)) weights_const[0] = weights_const[0][:, 0:nr_const] weights_const[1] = weights_const[1][0:nr_const] elif layer_type == "Conv2D": #Put the former weights into the layer weights_const = list(np.copy(weights)) weights_const[0] = weights_const[0][:, :, :, 0:nr_const] weights_const[1] = weights_const[1][0:nr_const] else: print("Unknown layer type") #return layer_name_const = layer_name + "_1" #rename model_keras_new.get_layer(layer_name_const).set_weights( weights_const) #Rest trainable part #this part will only exist if nr_nodes-nr_const>0: if nr_nodes - nr_const > 0: if layer_type == "Dense": #Get the weights weights_rest = list(np.copy(weights)) weights_rest[0] = weights_rest[0][:, nr_const:] weights_rest[1] = weights_rest[1][nr_const:] if layer_type == "Conv2D": #Get the weights weights_rest = list(np.copy(weights)) weights_rest[0] = weights_rest[0][:, :, :, nr_const:] weights_rest[1] = weights_rest[1][nr_const:] layer_name_rest = layer_name + "_2" #rename model_keras_new.get_layer(layer_name_rest).set_weights( weights_rest) return model_keras_new
def build_pruned_model(model, new_model_param, layer_types, num_new_neurons, num_new_filters, comp): """ The new number of neurons and filters are changed in the model config. Load the new weight matrices into the model. Args: model: Model which should be pruned new_model_param: Stores the new weights of the model layer_types: The types of all layers of the model num_new_neurons: Number of neurons of the dense layers num_new_filters: Number of filters of the conv layers Return: pruned_model: New model after pruning all dense and conv layers """ model_config = model.get_config() ''' For functional model first layer is the input layer. For sequential model the first layer is the layer after the input layer ''' a = 1 if layer_types[0] == 'InputLayer': a = 0 for i in range(0, len(model_config['layers']) - 3): if model_config['layers'][i + a][ 'class_name'] == "Dense": #i+1 because first layer of model is the inputlayer print("Dense") model_config['layers'][i + a]['config']['units'] = num_new_neurons[i] elif model_config['layers'][i + a]['class_name'] == "Conv2D": print("Conv2D") model_config['layers'][i + a]['config']['filters'] = num_new_filters[i] elif model_config['layers'][i + a]['class_name'] == "Reshape": temp_list = list( model_config['layers'][i + a]['config']['target_shape']) cur_layer = i cur_filters = num_new_filters[cur_layer] #Get number of filters of last Conv layer if cur_filters == 0: while cur_filters == 0: cur_layer -= 1 cur_filters = num_new_filters[cur_layer] temp_list[2] = cur_filters temp_tuple = tuple(temp_list) model_config['layers'][i + a]['config']['target_shape'] = temp_tuple else: print("No Dense or Conv2D") print("Before pruning:") model.summary() if "Sequential" in str(model): pruned_model = Sequential.from_config(model_config) elif "Functional" in str(model): pruned_model = Model.from_config(model_config) print("After pruning:") pruned_model.summary() for i in range(0, len(pruned_model.layers)): if len(new_model_param[i]) != 0: pruned_model.layers[i].set_weights(new_model_param[i]) else: None pruned_model.compile(**comp) return pruned_model