diff --git a/demo/imagenet_reader.py b/demo/imagenet_reader.py index 295ce218df79b1a6717abc46d5f49d2d999cd13f..01aa65a50ea4d556a89beff0541b9ddae87be604 100644 --- a/demo/imagenet_reader.py +++ b/demo/imagenet_reader.py @@ -156,8 +156,7 @@ def _reader_creator(file_list, for line in lines: if mode == 'train' or mode == 'val': img_path, label = line.split() - img_path = os.path.join( - os.path.join(data_dir, mode), img_path) + img_path = os.path.join(data_dir, img_path) yield img_path, int(label) elif mode == 'test': img_path = os.path.join(data_dir, line) diff --git a/paddleslim/prune/pruner.py b/paddleslim/prune/pruner.py index b6029513d84dda05b8dc0c15c58863c4a99efb46..9fc9b24ba5ec441e042d5217d77ca277a14f89d5 100644 --- a/paddleslim/prune/pruner.py +++ b/paddleslim/prune/pruner.py @@ -15,6 +15,7 @@ import logging import sys import numpy as np +from functools import reduce import paddle.fluid as fluid import copy from ..core import VarWrapper, OpWrapper, GraphWrapper @@ -152,6 +153,27 @@ class Pruner(): reduce_dims = [i for i in range(len(param_t.shape)) if i != axis] criterions = np.sum(np.abs(param_t), axis=tuple(reduce_dims)) pruned_idx = criterions.argsort()[:prune_num] + elif self.criterion == 'geometry_median': + param_t = np.array(scope.find_var(param).get_tensor()) + prune_num = int(round(param_t.shape[axis] * ratio)) + + def get_distance_sum(param, out_idx): + w = param.view() + reduce_dims = reduce(lambda x, y: x * y, param.shape[1:]) + w.shape = param.shape[0], reduce_dims + selected_filter = np.tile(w[out_idx], (w.shape[0], 1)) + x = w - selected_filter + x = np.sqrt(np.sum(x * x, -1)) + return x.sum() + + dist_sum_list = [] + for out_i in range(param_t.shape[0]): + dist_sum = get_distance_sum(param_t, out_i) + dist_sum_list.append((dist_sum, out_i)) + min_gm_filters = sorted( + dist_sum_list, key=lambda x: x[0])[:prune_num] + pruned_idx = [x[1] for x in min_gm_filters] + elif self.criterion == "batch_norm_scale": param_var = graph.var(param) conv_op = param_var.outputs()[0] diff --git a/tests/test_fpgm_prune.py b/tests/test_fpgm_prune.py new file mode 100644 index 0000000000000000000000000000000000000000..2f90dddcb7bb6e0658850288e594b7fae935e5d8 --- /dev/null +++ b/tests/test_fpgm_prune.py @@ -0,0 +1,82 @@ +# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License" +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import sys +sys.path.append("../") +import unittest +import paddle.fluid as fluid +from paddleslim.prune import Pruner +from layers import conv_bn_layer + + +class TestPrune(unittest.TestCase): + def test_prune(self): + main_program = fluid.Program() + startup_program = fluid.Program() + # X X O X O + # conv1-->conv2-->sum1-->conv3-->conv4-->sum2-->conv5-->conv6 + # | ^ | ^ + # |____________| |____________________| + # + # X: prune output channels + # O: prune input channels + with fluid.program_guard(main_program, startup_program): + input = fluid.data(name="image", shape=[None, 3, 16, 16]) + conv1 = conv_bn_layer(input, 8, 3, "conv1") + conv2 = conv_bn_layer(conv1, 8, 3, "conv2") + sum1 = conv1 + conv2 + conv3 = conv_bn_layer(sum1, 8, 3, "conv3") + conv4 = conv_bn_layer(conv3, 8, 3, "conv4") + sum2 = conv4 + sum1 + conv5 = conv_bn_layer(sum2, 8, 3, "conv5") + conv6 = conv_bn_layer(conv5, 8, 3, "conv6") + + shapes = {} + for param in main_program.global_block().all_parameters(): + shapes[param.name] = param.shape + + place = fluid.CPUPlace() + exe = fluid.Executor(place) + scope = fluid.Scope() + exe.run(startup_program, scope=scope) + criterion = 'geometry_median' + pruner = Pruner(criterion) + main_program, _, _ = pruner.prune( + main_program, + scope, + params=["conv4_weights"], + ratios=[0.5], + place=place, + lazy=False, + only_graph=False, + param_backup=None, + param_shape_backup=None) + + shapes = { + "conv1_weights": (4L, 3L, 3L, 3L), + "conv2_weights": (4L, 4L, 3L, 3L), + "conv3_weights": (8L, 4L, 3L, 3L), + "conv4_weights": (4L, 8L, 3L, 3L), + "conv5_weights": (8L, 4L, 3L, 3L), + "conv6_weights": (8L, 8L, 3L, 3L) + } + + for param in main_program.global_block().all_parameters(): + if "weights" in param.name: + print("param: {}; param shape: {}".format(param.name, + param.shape)) + self.assertTrue(param.shape == shapes[param.name]) + + +if __name__ == '__main__': + unittest.main()