def test_delete_all_channels_in_long_branch(): input_1 = Input(shape=(20, 20, 3)) conv_1 = Conv2D(2, [3, 3], name='conv_1') conv_2 = Conv2D(3, [3, 3], name='conv_2') conv_3 = Conv2D(4, [1, 1], name='conv_3') cat_1 = Concatenate(name='cat_1') x = conv_1(input_1) x = conv_3(x) y = conv_2(input_1) output_1 = cat_1([x, y]) model_1 = utils.clean_copy(Model(input_1, output_1)) surgeon = Surgeon(model_1, copy=True) surgeon.add_job('delete_channels', model_1.get_layer('conv_1'), channels=[0, 1]) model_2 = surgeon.operate() output_1 = conv_2(input_1) model_2_exp = utils.clean_copy(Model(input_1, output_1)) config_1 = model_2.get_config() config_2 = model_2_exp.get_config() config_2['name'] = config_1['name'] # make the config names identical assert config_1 == config_2
def layer_test_helper_flatten_1d(layer, channel_index): # This should test that the output is the correct shape so it should pass # into a Dense layer rather than a Conv layer. # The weighted layer is the previous layer, # Create model main_input = Input(shape=list(random.randint(10, 20, size=2))) x = Conv1D(3, 3)(main_input) x = layer(x) x = Flatten()(x) main_output = Dense(5)(x) model = Model(inputs=main_input, outputs=main_output) # Delete channels del_layer_index = 1 next_layer_index = 4 del_layer = model.layers[del_layer_index] surgeon = Surgeon(model) surgeon.add_job('delete_channels', del_layer, channels=channel_index) new_model = surgeon.operate() new_w = new_model.layers[next_layer_index].get_weights() # Calculate next layer's correct weights flat_sz = np.prod(layer.get_output_shape_at(0)[1:]) channel_count = getattr(del_layer, utils.get_channels_attr(del_layer)) channel_index = [i % channel_count for i in channel_index] delete_indices = [ x + i for i in range(0, flat_sz, channel_count) for x in channel_index ] correct_w = model.layers[next_layer_index].get_weights() correct_w[0] = np.delete(correct_w[0], delete_indices, axis=0) assert weights_equal(correct_w, new_w)
def test_rebuild_submodel(model_2): output_nodes = [] for output in model_2.outputs: layer, node_index, tensor_index = output._keras_history output_nodes.append(get_inbound_nodes(layer)[node_index]) surgeon = Surgeon(model_2) outputs, _ = surgeon._rebuild_graph(model_2.inputs, output_nodes) new_model = Model(model_2.inputs, outputs) assert compare_models(model_2, new_model)
def test_delete_channels_merge_concatenate(channel_index, data_format): # This should test that the output is the correct shape so it should pass # into a Dense layer rather than a Conv layer. # The weighted layer is the previous layer, # Create model if data_format == 'channels_first': axis = 1 elif data_format == 'channels_last': axis = -1 else: raise ValueError input_shape = list(random.randint(10, 20, size=3)) input_1 = Input(shape=input_shape) input_2 = Input(shape=input_shape) x = Conv2D(3, [3, 3], data_format=data_format, name='conv_1')(input_1) y = Conv2D(3, [3, 3], data_format=data_format, name='conv_2')(input_2) x = Concatenate(axis=axis, name='cat_1')([x, y]) x = Flatten()(x) main_output = Dense(5, name='dense_1')(x) model = Model(inputs=[input_1, input_2], outputs=main_output) old_w = model.get_layer('dense_1').get_weights() # Delete channels layer = model.get_layer('cat_1') del_layer = model.get_layer('conv_1') surgeon = Surgeon(model, copy=True) surgeon.add_job('delete_channels', del_layer, channels=channel_index) new_model = surgeon.operate() new_w = new_model.get_layer('dense_1').get_weights() # Calculate next layer's correct weights flat_sz = np.prod(layer.get_output_shape_at(0)[1:]) channel_count = getattr(del_layer, utils.get_channels_attr(del_layer)) channel_index = [i % channel_count for i in channel_index] if data_format == 'channels_first': delete_indices = [ x * flat_sz // 2 // channel_count + i for x in channel_index for i in range( 0, flat_sz // 2 // channel_count, ) ] elif data_format == 'channels_last': delete_indices = [ x + i for i in range(0, flat_sz, channel_count * 2) for x in channel_index ] else: raise ValueError correct_w = model.get_layer('dense_1').get_weights() correct_w[0] = np.delete(correct_w[0], delete_indices, axis=0) assert weights_equal(correct_w, new_w)
def prune(self, keep_ratio): surgeon = Surgeon(self.model, copy=True) filter_masks = self._produce_filter_pruning_mask(keep_ratio) for filter_mask, layer in zip(filter_masks, self.model.layers): drop_indices = np.argwhere(filter_mask)[:, 0] if drop_indices.size == filter_mask.size: drop_indices = drop_indices[1:] if drop_indices.size: surgeon.add_job("delete_channels", layer, channels=drop_indices) return surgeon.operate()
def prune_model(model, apoz_df, n_channels_delete): # Identify 5% of channels with the highest APoZ in model sorted_apoz_df = apoz_df.sort_values('apoz', ascending=False) high_apoz_index = sorted_apoz_df.iloc[0:n_channels_delete, :] # Create the Surgeon and add a 'delete_channels' job for each layer # whose channels are to be deleted. surgeon = Surgeon(model, copy=True) for name in high_apoz_index.index.unique().values: channels = list(pd.Series(high_apoz_index.loc[name, 'index'], dtype=np.int64).values) surgeon.add_job('delete_channels', model.get_layer(name), channels=channels) # Delete channels return surgeon.operate()
def prune(self, x, y, keep_ratio): saliencies = self._get_saliencies([x, y]) filter_masks, filter_saliencies = self._produce_filter_pruning_mask( saliencies, keep_ratio) surgeon = Surgeon(self.model, copy=True) for filter_mask, saliency, weight in zip(filter_masks, filter_saliencies, self.weights_of_interest): layer_name = self.weight_to_layer[weight.name] layer = self.model.get_layer(name=layer_name) drop_indices = np.squeeze(np.argwhere(filter_mask)) if drop_indices.size == filter_mask.size: best_filter = saliency.argmax() drop_indices = np.delete(drop_indices, best_filter) if drop_indices.shape: surgeon.add_job("delete_channels", layer, channels=drop_indices) return surgeon.operate()
def test_delete_channels_downstream_sharing(): # Create all model layers input_1 = Input(shape=(5, )) dense_1 = Dense(4, name='dense_1') dense_2 = Dense(4, name='dense_2') dense_3 = Dense(3, name='dense_3') # Create the base model x = dense_1(input_1) y = dense_2(input_1) output_1 = dense_3(x) output_2 = dense_3(y) model_1 = utils.clean_copy(Model(input_1, [output_1, output_2])) # Delete channels from dense_1 and dense_2 surgeon = Surgeon(model_1) surgeon.add_job('delete_channels', model_1.get_layer(dense_1.name), channels=[0]) surgeon.add_job('delete_channels', model_1.get_layer(dense_2.name), channels=[1]) model_2 = surgeon.operate() # Create the expected model # input_1 = Input(shape=(5,)) dense_1_exp = Dense(3, name='dense_1') dense_2_exp = Dense(3, name='dense_2') dense_3_exp = Dense(3, name='dense_3') # Create the base model x = dense_1_exp(input_1) y = dense_2_exp(input_1) output_1 = dense_3_exp(x) output_2 = dense_3_exp(y) model_2_exp = utils.clean_copy(Model(input_1, [output_1, output_2])) config_1 = model_2.get_config() config_2 = model_2_exp.get_config() config_2['name'] = config_1['name'] # make the config names identical assert config_1 == config_2