module.py 11.0 KB
Newer Older
W
wuzewu 已提交
1 2 3 4 5
# coding=utf-8
from __future__ import absolute_import

import ast
import argparse
6
import os
W
wuzewu 已提交
7 8
from functools import partial

9
import yaml
W
wuzewu 已提交
10 11 12 13
import numpy as np
import paddle.fluid as fluid
import paddlehub as hub
from paddle.fluid.core import PaddleTensor, AnalysisConfig, create_paddle_predictor
14 15
from paddlehub.module.module import moduleinfo, runnable, serving
from paddlehub.common.paddle_helper import add_vars_prefix
W
wuzewu 已提交
16 17

from ssd_vgg16_300_coco2017.vgg import VGG
18 19
from ssd_vgg16_300_coco2017.processor import load_label_info, postprocess, base64_to_cv2
from ssd_vgg16_300_coco2017.data_feed import reader
W
wuzewu 已提交
20 21 22 23


@moduleinfo(
    name="ssd_vgg16_300_coco2017",
W
wuzewu 已提交
24
    version="1.0.1",
W
wuzewu 已提交
25 26 27
    type="cv/object_detection",
    summary="SSD with backbone VGG16, trained with dataset COCO.",
    author="paddlepaddle",
W
wuzewu 已提交
28
    author_email="paddle-dev@baidu.com")
W
wuzewu 已提交
29 30
class SSDVGG16(hub.Module):
    def _initialize(self):
W
wuzewu 已提交
31 32
        self.default_pretrained_model_path = os.path.join(self.directory, "ssd_vgg16_300_model")
        self.label_names = load_label_info(os.path.join(self.directory, "label_file.txt"))
33
        self.model_config = None
W
wuzewu 已提交
34 35 36
        self._set_config()

    def _set_config(self):
37
        # predictor config setting.
W
wuzewu 已提交
38 39 40
        cpu_config = AnalysisConfig(self.default_pretrained_model_path)
        cpu_config.disable_glog_info()
        cpu_config.disable_gpu()
41
        cpu_config.switch_ir_optim(False)
W
wuzewu 已提交
42 43 44 45 46 47 48 49 50 51 52 53 54 55
        self.cpu_predictor = create_paddle_predictor(cpu_config)

        try:
            _places = os.environ["CUDA_VISIBLE_DEVICES"]
            int(_places[0])
            use_gpu = True
        except:
            use_gpu = False
        if use_gpu:
            gpu_config = AnalysisConfig(self.default_pretrained_model_path)
            gpu_config.disable_glog_info()
            gpu_config.enable_use_gpu(memory_pool_init_size_mb=500, device_id=0)
            self.gpu_predictor = create_paddle_predictor(gpu_config)

56 57 58 59 60 61 62
        # model config setting.
        if not self.model_config:
            with open(os.path.join(self.directory, 'config.yml')) as fp:
                self.model_config = yaml.load(fp.read(), Loader=yaml.FullLoader)

        self.multi_box_head_config = self.model_config['MultiBoxHead']
        self.output_decoder_config = self.model_config['SSDOutputDecoder']
W
wuzewu 已提交
63

64
    def context(self, trainable=True, pretrained=True, get_prediction=False):
W
wuzewu 已提交
65
        """
66 67 68 69 70 71 72 73 74 75 76 77 78
        Distill the Head Features, so as to perform transfer learning.

        Args:
            trainable (bool): whether to set parameters trainable.
            pretrained (bool): whether to load default pretrained model.
            get_prediction (bool): whether to get prediction.

        Returns:
             inputs(dict): the input variables.
             outputs(dict): the output variables.
             context_prog (Program): the program to execute transfer learning.
        """
        context_prog = fluid.Program()
W
wuzewu 已提交
79
        startup_program = fluid.Program()
80
        with fluid.program_guard(context_prog, startup_program):
W
wuzewu 已提交
81 82
            with fluid.unique_name.guard():
                # image
W
wuzewu 已提交
83
                image = fluid.layers.data(name='image', shape=[3, 300, 300], dtype='float32')
W
wuzewu 已提交
84
                # backbone
W
wuzewu 已提交
85
                backbone = VGG(depth=16, with_extra_blocks=True, normalizations=[20., -1, -1, -1, -1, -1])
86
                # body_feats
W
wuzewu 已提交
87
                body_feats = backbone(image)
88
                # im_size
W
wuzewu 已提交
89
                im_size = fluid.layers.data(name='im_size', shape=[2], dtype='int32')
90 91 92
                # var_prefix
                var_prefix = '@HUB_{}@'.format(self.name)
                # names of inputs
W
wuzewu 已提交
93
                inputs = {'image': var_prefix + image.name, 'im_size': var_prefix + im_size.name}
94 95 96
                # names of outputs
                if get_prediction:
                    locs, confs, box, box_var = fluid.layers.multi_box_head(
W
wuzewu 已提交
97
                        inputs=body_feats, image=image, num_classes=81, **self.multi_box_head_config)
98
                    pred = fluid.layers.detection_output(
W
wuzewu 已提交
99
                        loc=locs, scores=confs, prior_box=box, prior_box_var=box_var, **self.output_decoder_config)
100 101
                    outputs = {'bbox_out': [var_prefix + pred.name]}
                else:
W
wuzewu 已提交
102
                    outputs = {'body_features': [var_prefix + var.name for var in body_feats]}
103 104 105 106 107

                # add_vars_prefix
                add_vars_prefix(context_prog, var_prefix)
                add_vars_prefix(fluid.default_startup_program(), var_prefix)
                # inputs
W
wuzewu 已提交
108
                inputs = {key: context_prog.global_block().vars[value] for key, value in inputs.items()}
109
                outputs = {
W
wuzewu 已提交
110
                    out_key: [context_prog.global_block().vars[varname] for varname in out_value]
111 112 113 114 115
                    for out_key, out_value in outputs.items()
                }
                # trainable
                for param in context_prog.global_block().iter_parameters():
                    param.trainable = trainable
W
wuzewu 已提交
116 117 118

                place = fluid.CPUPlace()
                exe = fluid.Executor(place)
119
                # pretrained
W
wuzewu 已提交
120 121 122
                if pretrained:

                    def _if_exist(var):
W
wuzewu 已提交
123
                        return os.path.exists(os.path.join(self.default_pretrained_model_path, var.name))
W
wuzewu 已提交
124

W
wuzewu 已提交
125
                    fluid.io.load_vars(exe, self.default_pretrained_model_path, predicate=_if_exist)
W
wuzewu 已提交
126 127 128
                else:
                    exe.run(startup_program)

129
                return inputs, outputs, context_prog
W
wuzewu 已提交
130 131 132 133 134

    def object_detection(self,
                         paths=None,
                         images=None,
                         batch_size=1,
135
                         use_gpu=False,
W
wuzewu 已提交
136 137 138 139 140
                         output_dir='detection_result',
                         score_thresh=0.5,
                         visualization=True):
        """API of Object Detection.

141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
        Args:
            paths (list[str]): The paths of images.
            images (list(numpy.ndarray)): images data, shape of each is [H, W, C]
            batch_size (int): batch size.
            use_gpu (bool): Whether to use gpu.
            output_dir (str): The path to store output images.
            visualization (bool): Whether to save image or not.
            score_thresh (float): threshold for object detecion.

        Returns:
            res (list[dict]): The result of coco2017 detecion. keys include 'data', 'save_path', the corresponding value is:
                data (dict): the result of object detection, keys include 'left', 'top', 'right', 'bottom', 'label', 'confidence', the corresponding value is:
                    left (float): The X coordinate of the upper left corner of the bounding box;
                    top (float): The Y coordinate of the upper left corner of the bounding box;
                    right (float): The X coordinate of the lower right corner of the bounding box;
                    bottom (float): The Y coordinate of the lower right corner of the bounding box;
                    label (str): The label of detection result;
                    confidence (float): The confidence of detection result.
                save_path (str, optional): The path to save output images.
W
wuzewu 已提交
160
        """
161 162
        paths = paths if paths else list()
        data_reader = partial(reader, paths, images)
W
wuzewu 已提交
163 164 165
        batch_reader = fluid.io.batch(data_reader, batch_size=batch_size)
        res = []
        for iter_id, feed_data in enumerate(batch_reader()):
166 167
            feed_data = np.array(feed_data)
            image_tensor = PaddleTensor(np.array(list(feed_data[:, 0])).copy())
W
wuzewu 已提交
168
            if use_gpu:
169
                data_out = self.gpu_predictor.run([image_tensor])
W
wuzewu 已提交
170
            else:
171 172 173
                data_out = self.cpu_predictor.run([image_tensor])

            output = postprocess(
W
wuzewu 已提交
174 175 176 177 178 179 180 181
                paths=paths,
                images=images,
                data_out=data_out,
                score_thresh=score_thresh,
                label_names=self.label_names,
                output_dir=output_dir,
                handle_id=iter_id * batch_size,
                visualization=visualization)
182
            res.extend(output)
W
wuzewu 已提交
183 184
        return res

W
wuzewu 已提交
185
    def save_inference_model(self, dirname, model_filename=None, params_filename=None, combined=True):
186 187 188 189 190
        if combined:
            model_filename = "__model__" if not model_filename else model_filename
            params_filename = "__params__" if not params_filename else params_filename
        place = fluid.CPUPlace()
        exe = fluid.Executor(place)
W
wuzewu 已提交
191

192 193
        program, feeded_var_names, target_vars = fluid.io.load_inference_model(
            dirname=self.default_pretrained_model_path, executor=exe)
W
wuzewu 已提交
194

195 196 197 198 199 200 201 202 203 204 205
        fluid.io.save_inference_model(
            dirname=dirname,
            main_program=program,
            executor=exe,
            feeded_var_names=feeded_var_names,
            target_vars=target_vars,
            model_filename=model_filename,
            params_filename=params_filename)

    @serving
    def serving_method(self, images, **kwargs):
W
wuzewu 已提交
206
        """
207
        Run as a service.
W
wuzewu 已提交
208
        """
209
        images_decode = [base64_to_cv2(image) for image in images]
W
wuzewu 已提交
210
        results = self.object_detection(images=images_decode, **kwargs)
211
        return results
W
wuzewu 已提交
212 213 214

    @runnable
    def run_cmd(self, argvs):
215 216 217
        """
        Run as a command.
        """
W
wuzewu 已提交
218
        self.parser = argparse.ArgumentParser(
219 220
            description="Run the {} module.".format(self.name),
            prog='hub run {}'.format(self.name),
W
wuzewu 已提交
221 222
            usage='%(prog)s',
            add_help=True)
W
wuzewu 已提交
223
        self.arg_input_group = self.parser.add_argument_group(title="Input options", description="Input data. Required")
W
wuzewu 已提交
224
        self.arg_config_group = self.parser.add_argument_group(
W
wuzewu 已提交
225
            title="Config options", description="Run configuration for controlling module behavior, not required.")
W
wuzewu 已提交
226 227 228
        self.add_module_config_arg()
        self.add_module_input_arg()
        args = self.parser.parse_args(argvs)
W
wuzewu 已提交
229
        results = self.object_detection(
230 231 232 233 234 235 236 237 238 239 240 241 242
            paths=[args.input_path],
            batch_size=args.batch_size,
            use_gpu=args.use_gpu,
            output_dir=args.output_dir,
            visualization=args.visualization,
            score_thresh=args.score_thresh)
        return results

    def add_module_config_arg(self):
        """
        Add the command config options.
        """
        self.arg_config_group.add_argument(
W
wuzewu 已提交
243
            '--use_gpu', type=ast.literal_eval, default=False, help="whether use GPU or not")
244
        self.arg_config_group.add_argument(
W
wuzewu 已提交
245
            '--output_dir', type=str, default='detection_result', help="The directory to save output images.")
246
        self.arg_config_group.add_argument(
W
wuzewu 已提交
247
            '--visualization', type=ast.literal_eval, default=False, help="whether to save output as images.")
248 249 250 251 252

    def add_module_input_arg(self):
        """
        Add the command input options.
        """
W
wuzewu 已提交
253 254
        self.arg_input_group.add_argument('--input_path', type=str, help="path to image.")
        self.arg_input_group.add_argument('--batch_size', type=ast.literal_eval, default=1, help="batch size.")
255
        self.arg_input_group.add_argument(
W
wuzewu 已提交
256
            '--score_thresh', type=ast.literal_eval, default=0.5, help="threshold for object detecion.")