def runTest(self): with fluid.unique_name.guard(): net = MulNet() ratios = {} ratios['conv2d_0.w_0'] = 0.5 pruners = [] pruner = L1NormFilterPruner(net, [2, 6, 3, 3], skip_leaves=False) pruners.append(pruner) pruner = FPGMFilterPruner(net, [2, 6, 3, 3], skip_leaves=False) pruners.append(pruner) pruner = L2NormFilterPruner(net, [2, 6, 3, 3], skip_leaves=False) pruners.append(pruner) shapes = { 'b': [3, 18], 'conv2d_0.w_0': [3, 6, 1, 1], 'conv2d_0.b_0': [3] } for pruner in pruners: plan = pruner.prune_vars(ratios, 0) for param in net.parameters(): if param.name not in shapes: shapes[param.name] = param.shape self.assertTrue(shapes[param.name] == param.shape) pruner.restore()
def runTest(self): with fluid.unique_name.guard(): net = paddle.vision.models.LeNet() optimizer = paddle.optimizer.Adam(learning_rate=0.001, parameters=net.parameters()) inputs = [Input([None, 1, 28, 28], 'float32', name='image')] labels = [Input([None, 1], 'int64', name='label')] model = paddle.Model(net, inputs, labels) model.prepare(optimizer, paddle.nn.CrossEntropyLoss(), paddle.metric.Accuracy(topk=(1, 5))) model.fit(self.train_dataset, epochs=1, batch_size=128, verbose=1) pruners = [] pruner = L1NormFilterPruner(net, [1, 1, 28, 28], opt=optimizer) pruners.append(pruner) pruner = FPGMFilterPruner(net, [1, 1, 28, 28], opt=optimizer) pruners.append(pruner) pruner = L2NormFilterPruner(net, [1, 1, 28, 28], opt=optimizer) pruners.append(pruner) def eval_fn(): result = model.evaluate(self.val_dataset, batch_size=128, verbose=1) return result['acc_top1'] sen_file = "_".join(["./dygraph_sen_", str(time.time())]) for pruner in pruners: sen = pruner.sensitive(eval_func=eval_fn, sen_file=sen_file, target_vars=self._param_names) model.fit(self.train_dataset, epochs=1, batch_size=128, verbose=1) base_acc = eval_fn() plan = pruner.sensitive_prune(0.01) pruner.restore() restore_acc = eval_fn() self.assertTrue(restore_acc == base_acc) plan = pruner.sensitive_prune(0.01, align=4) for param in net.parameters(): if param.name in self._param_names: print(f"name: {param.name}; shape: {param.shape}") self.assertTrue(param.shape[0] % 4 == 0) pruner.restore()
def runTest(self): with fluid.unique_name.guard(): net = paddle.vision.models.mobilenet_v1() ratios = {} for param in net.parameters(): if len(param.shape) == 4: ratios[param.name] = 0.5 pruners = [] pruner = L1NormFilterPruner(net, [1, 3, 128, 128]) pruners.append(pruner) pruner = FPGMFilterPruner(net, [1, 3, 128, 128]) pruners.append(pruner) pruner = L2NormFilterPruner(net, [1, 3, 128, 128]) pruners.append(pruner) shapes = {} for pruner in pruners: plan = pruner.prune_vars(ratios, 0) for param in net.parameters(): if param.name not in shapes: shapes[param.name] = param.shape assert (shapes[param.name] == param.shape) pruner.restore()
def main(config, device, logger, vdl_writer): # init dist environment if config['Global']['distributed']: dist.init_parallel_env() global_config = config['Global'] # build dataloader train_dataloader = build_dataloader(config, 'Train', device, logger) if config['Eval']: valid_dataloader = build_dataloader(config, 'Eval', device, logger) else: valid_dataloader = None # build post process post_process_class = build_post_process(config['PostProcess'], global_config) # build model # for rec algorithm if hasattr(post_process_class, 'character'): char_num = len(getattr(post_process_class, 'character')) config['Architecture']["Head"]['out_channels'] = char_num model = build_model(config['Architecture']) flops = paddle.flops(model, [1, 3, 640, 640]) logger.info(f"FLOPs before pruning: {flops}") from paddleslim.dygraph import FPGMFilterPruner model.train() pruner = FPGMFilterPruner(model, [1, 3, 640, 640]) # build loss loss_class = build_loss(config['Loss']) # build optim optimizer, lr_scheduler = build_optimizer( config['Optimizer'], epochs=config['Global']['epoch_num'], step_each_epoch=len(train_dataloader), parameters=model.parameters()) # build metric eval_class = build_metric(config['Metric']) # load pretrain model pre_best_model_dict = init_model(config, model, logger, optimizer) logger.info( 'train dataloader has {} iters, valid dataloader has {} iters'.format( len(train_dataloader), len(valid_dataloader))) # build metric eval_class = build_metric(config['Metric']) logger.info( 'train dataloader has {} iters, valid dataloader has {} iters'.format( len(train_dataloader), len(valid_dataloader))) def eval_fn(): metric = program.eval(model, valid_dataloader, post_process_class, eval_class) logger.info(f"metric['hmean']: {metric['hmean']}") return metric['hmean'] params_sensitive = pruner.sensitive(eval_func=eval_fn, sen_file="./sen.pickle", skip_vars=[ "conv2d_57.w_0", "conv2d_transpose_2.w_0", "conv2d_transpose_3.w_0" ]) logger.info( "The sensitivity analysis results of model parameters saved in sen.pickle" ) # calculate pruned params's ratio params_sensitive = pruner._get_ratios_by_loss(params_sensitive, loss=0.02) for key in params_sensitive.keys(): logger.info(f"{key}, {params_sensitive[key]}") plan = pruner.prune_vars(params_sensitive, [0]) for param in model.parameters(): if ("weights" in param.name and "conv" in param.name) or ("w_0" in param.name and "conv2d" in param.name): logger.info(f"{param.name}: {param.shape}") flops = paddle.flops(model, [1, 3, 640, 640]) logger.info(f"FLOPs after pruning: {flops}") # start train program.train(config, train_dataloader, valid_dataloader, device, model, loss_class, optimizer, lr_scheduler, post_process_class, eval_class, pre_best_model_dict, logger, vdl_writer)
def main(config, device, logger, vdl_writer): global_config = config['Global'] # build dataloader valid_dataloader = build_dataloader(config, 'Eval', device, logger) # build post process post_process_class = build_post_process(config['PostProcess'], global_config) # build model # for rec algorithm if hasattr(post_process_class, 'character'): char_num = len(getattr(post_process_class, 'character')) config['Architecture']["Head"]['out_channels'] = char_num model = build_model(config['Architecture']) flops = paddle.flops(model, [1, 3, 640, 640]) logger.info(f"FLOPs before pruning: {flops}") from paddleslim.dygraph import FPGMFilterPruner model.train() pruner = FPGMFilterPruner(model, [1, 3, 640, 640]) # build metric eval_class = build_metric(config['Metric']) def eval_fn(): metric = program.eval(model, valid_dataloader, post_process_class, eval_class) logger.info(f"metric['hmean']: {metric['hmean']}") return metric['hmean'] params_sensitive = pruner.sensitive(eval_func=eval_fn, sen_file="./sen.pickle", skip_vars=[ "conv2d_57.w_0", "conv2d_transpose_2.w_0", "conv2d_transpose_3.w_0" ]) logger.info( "The sensitivity analysis results of model parameters saved in sen.pickle" ) # calculate pruned params's ratio params_sensitive = pruner._get_ratios_by_loss(params_sensitive, loss=0.02) for key in params_sensitive.keys(): logger.info(f"{key}, {params_sensitive[key]}") plan = pruner.prune_vars(params_sensitive, [0]) flops = paddle.flops(model, [1, 3, 640, 640]) logger.info(f"FLOPs after pruning: {flops}") # load pretrain model pre_best_model_dict = init_model(config, model, logger, None) metric = program.eval(model, valid_dataloader, post_process_class, eval_class) logger.info(f"metric['hmean']: {metric['hmean']}") # start export model from paddle.jit import to_static infer_shape = [3, -1, -1] if config['Architecture']['model_type'] == "rec": infer_shape = [3, 32, -1] # for rec model, H must be 32 if 'Transform' in config['Architecture'] and config['Architecture'][ 'Transform'] is not None and config['Architecture'][ 'Transform']['name'] == 'TPS': logger.info( 'When there is tps in the network, variable length input is not supported, and the input size needs to be the same as during training' ) infer_shape[-1] = 100 model = to_static(model, input_spec=[ paddle.static.InputSpec(shape=[None] + infer_shape, dtype='float32') ]) save_path = '{}/inference'.format(config['Global']['save_inference_dir']) paddle.jit.save(model, save_path) logger.info('inference model is saved to {}'.format(save_path))
def main(config, device, logger, vdl_writer): # init dist environment if config['Global']['distributed']: dist.init_parallel_env() global_config = config['Global'] # build dataloader train_dataloader = build_dataloader(config, 'Train', device, logger) if config['Eval']: valid_dataloader = build_dataloader(config, 'Eval', device, logger) else: valid_dataloader = None # build post process post_process_class = build_post_process(config['PostProcess'], global_config) # build model # for rec algorithm if hasattr(post_process_class, 'character'): char_num = len(getattr(post_process_class, 'character')) config['Architecture']["Head"]['out_channels'] = char_num model = build_model(config['Architecture']) if config['Architecture']['model_type'] == 'det': input_shape = [1, 3, 640, 640] elif config['Architecture']['model_type'] == 'rec': input_shape = [1, 3, 32, 320] flops = paddle.flops(model, input_shape) logger.info("FLOPs before pruning: {}".format(flops)) from paddleslim.dygraph import FPGMFilterPruner model.train() pruner = FPGMFilterPruner(model, input_shape) # build loss loss_class = build_loss(config['Loss']) # build optim optimizer, lr_scheduler = build_optimizer( config['Optimizer'], epochs=config['Global']['epoch_num'], step_each_epoch=len(train_dataloader), parameters=model.parameters()) # build metric eval_class = build_metric(config['Metric']) # load pretrain model pre_best_model_dict = load_model(config, model, optimizer) logger.info( 'train dataloader has {} iters, valid dataloader has {} iters'.format( len(train_dataloader), len(valid_dataloader))) # build metric eval_class = build_metric(config['Metric']) logger.info( 'train dataloader has {} iters, valid dataloader has {} iters'.format( len(train_dataloader), len(valid_dataloader))) def eval_fn(): metric = program.eval(model, valid_dataloader, post_process_class, eval_class, False) if config['Architecture']['model_type'] == 'det': main_indicator = 'hmean' else: main_indicator = 'acc' logger.info("metric[{}]: {}".format(main_indicator, metric[main_indicator])) return metric[main_indicator] run_sensitive_analysis = False """ run_sensitive_analysis=True: Automatically compute the sensitivities of convolutions in a model. The sensitivity of a convolution is the losses of accuracy on test dataset in differenct pruned ratios. The sensitivities can be used to get a group of best ratios with some condition. run_sensitive_analysis=False: Set prune trim ratio to a fixed value, such as 10%. The larger the value, the more convolution weights will be cropped. """ if run_sensitive_analysis: params_sensitive = pruner.sensitive( eval_func=eval_fn, sen_file="./deploy/slim/prune/sen.pickle", skip_vars=[ "conv2d_57.w_0", "conv2d_transpose_2.w_0", "conv2d_transpose_3.w_0" ]) logger.info( "The sensitivity analysis results of model parameters saved in sen.pickle" ) # calculate pruned params's ratio params_sensitive = pruner._get_ratios_by_loss(params_sensitive, loss=0.02) for key in params_sensitive.keys(): logger.info("{}, {}".format(key, params_sensitive[key])) else: params_sensitive = {} for param in model.parameters(): if 'transpose' not in param.name and 'linear' not in param.name: # set prune ratio as 10%. The larger the value, the more convolution weights will be cropped params_sensitive[param.name] = 0.1 plan = pruner.prune_vars(params_sensitive, [0]) flops = paddle.flops(model, input_shape) logger.info("FLOPs after pruning: {}".format(flops)) # start train program.train(config, train_dataloader, valid_dataloader, device, model, loss_class, optimizer, lr_scheduler, post_process_class, eval_class, pre_best_model_dict, logger, vdl_writer)