# Copyright (c) 2019 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. from __future__ import absolute_import from __future__ import division from __future__ import print_function import os import time import multiprocessing import numpy as np from collections import deque, OrderedDict from paddle.fluid.contrib.slim.core import Compressor from paddle.fluid.framework import IrGraph def set_paddle_flags(**kwargs): for key, value in kwargs.items(): if os.environ.get(key, None) is None: os.environ[key] = str(value) # NOTE(paddle-dev): All of these flags should be set before # `import paddle`. Otherwise, it would not take any effect. set_paddle_flags( FLAGS_eager_delete_tensor_gb=0, # enable GC to save memory ) from paddle import fluid import sys sys.path.append("../../") from ppdet.core.workspace import load_config, merge_config, create from ppdet.data.data_feed import create_reader from ppdet.utils.eval_utils import parse_fetches, eval_results from ppdet.utils.stats import TrainingStats from ppdet.utils.cli import ArgsParser from ppdet.utils.check import check_gpu import ppdet.utils.checkpoint as checkpoint from ppdet.modeling.model_input import create_feed import logging FORMAT = '%(asctime)s-%(levelname)s: %(message)s' logging.basicConfig(level=logging.INFO, format=FORMAT) logger = logging.getLogger(__name__) def eval_run(exe, compile_program, reader, keys, values, cls, test_feed): """ Run evaluation program, return program outputs. """ iter_id = 0 results = [] if len(cls) != 0: values = [] for i in range(len(cls)): _, accum_map = cls[i].get_map_var() cls[i].reset(exe) values.append(accum_map) images_num = 0 start_time = time.time() has_bbox = 'bbox' in keys for data in reader(): data = test_feed.feed(data) feed_data = {'image': data['image'], 'im_size': data['im_size']} outs = exe.run(compile_program, feed=feed_data, fetch_list=[values[0]], return_numpy=False) outs.append(data['gt_box']) outs.append(data['gt_label']) outs.append(data['is_difficult']) res = { k: (np.array(v), v.recursive_sequence_lengths()) for k, v in zip(keys, outs) } results.append(res) if iter_id % 100 == 0: logger.info('Test iter {}'.format(iter_id)) iter_id += 1 images_num += len(res['bbox'][1][0]) if has_bbox else 1 logger.info('Test finish iter {}'.format(iter_id)) end_time = time.time() fps = images_num / (end_time - start_time) if has_bbox: logger.info('Total number of images: {}, inference time: {} fps.'. format(images_num, fps)) else: logger.info('Total iteration: {}, inference time: {} batch/s.'.format( images_num, fps)) return results def main(): cfg = load_config(FLAGS.config) if 'architecture' in cfg: main_arch = cfg.architecture else: raise ValueError("'architecture' not specified in config file.") merge_config(FLAGS.opt) if 'log_iter' not in cfg: cfg.log_iter = 20 # check if set use_gpu=True in paddlepaddle cpu version check_gpu(cfg.use_gpu) if cfg.use_gpu: devices_num = fluid.core.get_cuda_device_count() else: devices_num = int( os.environ.get('CPU_NUM', multiprocessing.cpu_count())) if 'train_feed' not in cfg: train_feed = create(main_arch + 'TrainFeed') else: train_feed = create(cfg.train_feed) if 'eval_feed' not in cfg: eval_feed = create(main_arch + 'EvalFeed') else: eval_feed = create(cfg.eval_feed) place = fluid.CUDAPlace(0) if cfg.use_gpu else fluid.CPUPlace() exe = fluid.Executor(place) lr_builder = create('LearningRate') optim_builder = create('OptimizerBuilder') # build program model = create(main_arch) _, train_feed_vars = create_feed(train_feed, False) train_fetches = model.train(train_feed_vars) loss = train_fetches['loss'] lr = lr_builder() opt = optim_builder(lr) opt.minimize(loss) #for v in fluid.default_main_program().list_vars(): # if "py_reader" not in v.name and "double_buffer" not in v.name and "generated_var" not in v.name: # print(v.name, v.shape) cfg.max_iters = 258 train_reader = create_reader(train_feed, cfg.max_iters, FLAGS.dataset_dir) exe.run(fluid.default_startup_program()) # parse train fetches train_keys, train_values, _ = parse_fetches(train_fetches) train_keys.append('lr') train_values.append(lr.name) train_fetch_list = [] for k, v in zip(train_keys, train_values): train_fetch_list.append((k, v)) print("train_fetch_list: {}".format(train_fetch_list)) eval_prog = fluid.Program() startup_prog = fluid.Program() with fluid.program_guard(eval_prog, startup_prog): with fluid.unique_name.guard(): model = create(main_arch) _, test_feed_vars = create_feed(eval_feed, False) fetches = model.eval(test_feed_vars) eval_prog = eval_prog.clone(True) eval_reader = create_reader(eval_feed, args_path=FLAGS.dataset_dir) test_data_feed = fluid.DataFeeder(test_feed_vars.values(), place) # parse eval fetches extra_keys = [] if cfg.metric == 'COCO': extra_keys = ['im_info', 'im_id', 'im_shape'] if cfg.metric == 'VOC': extra_keys = ['gt_box', 'gt_label', 'is_difficult'] eval_keys, eval_values, eval_cls = parse_fetches(fetches, eval_prog, extra_keys) eval_fetch_list = [] for k, v in zip(eval_keys, eval_values): eval_fetch_list.append((k, v)) print("eval_fetch_list: {}".format(eval_fetch_list)) exe.run(startup_prog) checkpoint.load_params(exe, fluid.default_main_program(), cfg.pretrain_weights) best_box_ap_list = [] def eval_func(program, scope): results = eval_run(exe, program, eval_reader, eval_keys, eval_values, eval_cls, test_data_feed) resolution = None is_bbox_normalized = False if 'mask' in results[0]: resolution = model.mask_head.resolution box_ap_stats = eval_results(results, eval_feed, cfg.metric, cfg.num_classes, resolution, is_bbox_normalized, FLAGS.output_eval) if len(best_box_ap_list) == 0: best_box_ap_list.append(box_ap_stats[0]) elif box_ap_stats[0] > best_box_ap_list[0]: best_box_ap_list[0] = box_ap_stats[0] logger.info("Best test box ap: {}".format(best_box_ap_list[0])) return best_box_ap_list[0] test_feed = [('image', test_feed_vars['image'].name), ('im_size', test_feed_vars['im_size'].name)] teacher_cfg = load_config(FLAGS.teacher_config) teacher_arch = teacher_cfg.architecture teacher_programs = [] teacher_program = fluid.Program() teacher_startup_program = fluid.Program() with fluid.program_guard(teacher_program, teacher_startup_program): with fluid.unique_name.guard('teacher_'): teacher_feed_vars = OrderedDict() for name, var in train_feed_vars.items(): teacher_feed_vars[name] = teacher_program.global_block( )._clone_variable( var, force_persistable=False) model = create(teacher_arch) train_fetches = model.train(teacher_feed_vars) #print("="*50+"teacher_model_params"+"="*50) #for v in teacher_program.list_vars(): # print(v.name, v.shape) #return exe.run(teacher_startup_program) assert FLAGS.teacher_pretrained and os.path.exists( FLAGS.teacher_pretrained ), "teacher_pretrained should be set when teacher_model is not None." def if_exist(var): return os.path.exists(os.path.join(FLAGS.teacher_pretrained, var.name)) fluid.io.load_vars( exe, FLAGS.teacher_pretrained, main_program=teacher_program, predicate=if_exist) teacher_programs.append(teacher_program.clone(for_test=True)) com = Compressor( place, fluid.global_scope(), fluid.default_main_program(), train_reader=train_reader, train_feed_list=[(key, value.name) for key, value in train_feed_vars.items()], train_fetch_list=train_fetch_list, eval_program=eval_prog, eval_reader=eval_reader, eval_feed_list=test_feed, eval_func={'map': eval_func}, eval_fetch_list=eval_fetch_list[0:1], save_eval_model=True, prune_infer_model=[["image", "im_size"], ["multiclass_nms_0.tmp_0"]], teacher_programs=teacher_programs, train_optimizer=None, distiller_optimizer=opt, log_period=20) com.config(FLAGS.slim_file) com.run() if __name__ == '__main__': parser = ArgsParser() parser.add_argument( "-t", "--teacher_config", default=None, type=str, help="Config file of teacher architecture.") parser.add_argument( "-s", "--slim_file", default=None, type=str, help="Config file of PaddleSlim.") parser.add_argument( "-r", "--resume_checkpoint", default=None, type=str, help="Checkpoint path for resuming training.") parser.add_argument( "--eval", action='store_true', default=False, help="Whether to perform evaluation in train") parser.add_argument( "--teacher_pretrained", default=None, type=str, help="Whether to use pretrained model.") parser.add_argument( "--output_eval", default=None, type=str, help="Evaluation directory, default is current directory.") parser.add_argument( "-d", "--dataset_dir", default=None, type=str, help="Dataset path, same as DataFeed.dataset.dataset_dir") FLAGS = parser.parse_args() main()