build.py 9.5 KB
Newer Older
T
tangwei 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
# 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.

T
tangwei 已提交
15
import copy
T
tangwei 已提交
16

T
tangwei 已提交
17 18
import paddle.fluid as fluid
from paddle.fluid.incubate.fleet.parameter_server.pslib import fleet
T
tangwei 已提交
19
import yaml
T
tangwei 已提交
20

21 22
from paddlerec.core.model import Model
from paddlerec.core.utils import table
T
tangwei 已提交
23

T
tangwei 已提交
24

X
xiexionghang 已提交
25
def create(config):
X
xiexionghang 已提交
26 27 28
    """
    Create a model instance by config
    Args:
T
tangwei 已提交
29
        config(dict) : desc model type and net
X
xiexionghang 已提交
30 31 32
    Return:
        Model Instance
    """
X
xiexionghang 已提交
33
    model = None
T
tangwei 已提交
34

X
xiexionghang 已提交
35
    if config['mode'] == 'fluid':
X
xionghang 已提交
36 37 38 39 40 41 42
        if config['layer_file'].endswith(".py"):
            model_class = envs.lazy_instance_by_fliename(config['layer_file'],
                                                         "Model")
            model = model_class(config)
        else:
            model = YamlModel(config)
            model.train()
X
xiexionghang 已提交
43
    return model
T
tangwei 已提交
44

X
xiexionghang 已提交
45

T
tangwei 已提交
46
class YamlModel(Model):
X
xiexionghang 已提交
47 48
    """R
    """
T
tangwei 已提交
49

X
xiexionghang 已提交
50
    def __init__(self, config):
X
xiexionghang 已提交
51 52
        """R
        """
T
tangwei 已提交
53
        Model.__init__(self, config)
T
tangwei 已提交
54 55 56 57 58
        self._config = config
        self._name = config['name']
        f = open(config['layer_file'], 'r')
        self._build_nodes = yaml.safe_load(f.read())
        self._build_phase = ['input', 'param', 'summary', 'layer']
T
tangwei 已提交
59 60 61 62 63 64
        self._build_param = {
            'layer': {},
            'inner_layer': {},
            'layer_extend': {},
            'model': {}
        }
T
tangwei 已提交
65
        self._inference_meta = {'dependency': {}, 'params': {}}
T
tangwei 已提交
66

T
tangwei 已提交
67
    def train_net(self):
X
xiexionghang 已提交
68 69 70 71 72 73 74 75 76
        """R
        build a fluid model with config
        Return:
            modle_instance(dict)
                train_program
                startup_program
                inference_param : all params name list
                table: table-meta to ps-server
        """
X
xiexionghang 已提交
77 78
        for layer in self._build_nodes['layer']:
            self._build_param['inner_layer'][layer['name']] = layer
T
tangwei 已提交
79

X
xiexionghang 已提交
80 81 82
        self._build_param['table'] = {}
        self._build_param['model']['train_program'] = fluid.Program()
        self._build_param['model']['startup_program'] = fluid.Program()
X
xiexionghang 已提交
83
        with fluid.program_guard(self._build_param['model']['train_program'], \
T
tangwei 已提交
84
                                 self._build_param['model']['startup_program']):
X
xiexionghang 已提交
85 86 87 88 89
            with fluid.unique_name.guard():
                for phase in self._build_phase:
                    if self._build_nodes[phase] is None:
                        continue
                    for node in self._build_nodes[phase]:
T
tangwei 已提交
90 91 92
                        exec ("""layer=layer.{}(node)""".format(node['class']))
                        layer_output, extend_output = layer.generate(
                            self._config['mode'], self._build_param)
X
xiexionghang 已提交
93
                        self._build_param['layer'][node['name']] = layer_output
T
tangwei 已提交
94 95
                        self._build_param['layer_extend'][node[
                            'name']] = extend_output
X
xiexionghang 已提交
96 97 98 99 100 101 102 103 104
                        if extend_output is None:
                            continue
                        if 'loss' in extend_output:
                            if self._cost is None:
                                self._cost = extend_output['loss']
                            else:
                                self._cost += extend_output['loss']
                        if 'data_var' in extend_output:
                            self._data_var += extend_output['data_var']
T
tangwei 已提交
105 106 107 108
                        if 'metric_label' in extend_output and extend_output[
                                'metric_label'] is not None:
                            self._metrics[extend_output[
                                'metric_label']] = extend_output['metric_dict']
X
xiexionghang 已提交
109 110

                        if 'inference_param' in extend_output:
X
xiexionghang 已提交
111 112
                            inference_param = extend_output['inference_param']
                            param_name = inference_param['name']
X
xiexionghang 已提交
113
                            if param_name not in self._build_param['table']:
T
tangwei 已提交
114 115 116 117 118 119 120 121 122
                                self._build_param['table'][param_name] = {
                                    'params': []
                                }
                                table_meta = table.TableMeta.alloc_new_table(
                                    inference_param['table_id'])
                                self._build_param['table'][param_name][
                                    '_meta'] = table_meta
                            self._build_param['table'][param_name][
                                'params'] += inference_param['params']
X
xiexionghang 已提交
123
        pass
T
tangwei 已提交
124

X
xiexionghang 已提交
125 126
    @classmethod
    def build_optimizer(self, params):
X
xiexionghang 已提交
127 128
        """R
        """
X
xiexionghang 已提交
129 130 131 132 133 134 135 136
        optimizer_conf = params['optimizer_conf']
        strategy = None
        if 'strategy' in optimizer_conf:
            strategy = optimizer_conf['strategy']
            stat_var_names = []
            metrics = params['metrics']
            for name in metrics:
                model_metrics = metrics[name]
T
tangwei 已提交
137 138 139 140
                stat_var_names += [
                    model_metrics[metric]['var'].name
                    for metric in model_metrics
                ]
X
xiexionghang 已提交
141
            strategy['stat_var_names'] = list(set(stat_var_names))
X
xiexionghang 已提交
142
        optimizer_generator = 'optimizer = fluid.optimizer.' + optimizer_conf['class'] + \
T
tangwei 已提交
143
                              '(learning_rate=' + str(optimizer_conf['learning_rate']) + ')'
T
tangwei 已提交
144
        exec (optimizer_generator)
X
xiexionghang 已提交
145 146 147 148
        optimizer = fleet.distributed_optimizer(optimizer, strategy=strategy)
        return optimizer

    def dump_model_program(self, path):
X
xiexionghang 已提交
149 150
        """R
        """
T
tangwei 已提交
151 152
        with open(path + '/' + self._name + '_main_program.pbtxt',
                  "w") as fout:
X
xiexionghang 已提交
153
            print >> fout, self._build_param['model']['train_program']
T
tangwei 已提交
154 155
        with open(path + '/' + self._name + '_startup_program.pbtxt',
                  "w") as fout:
X
xiexionghang 已提交
156 157 158 159
            print >> fout, self._build_param['model']['startup_program']
        pass

    def shrink(self, params):
X
xiexionghang 已提交
160 161
        """R
        """
X
xiexionghang 已提交
162 163 164
        scope = params['scope']
        decay = params['decay']
        for param_table in self._build_param['table']:
T
tangwei 已提交
165 166
            table_id = self._build_param['table'][param_table][
                '_meta']._table_id
X
xiexionghang 已提交
167 168 169
            fleet.shrink_dense_table(decay, scope=scope, table_id=table_id)

    def dump_inference_program(self, inference_layer, path):
X
xiexionghang 已提交
170 171
        """R
        """
X
xiexionghang 已提交
172 173 174
        pass

    def dump_inference_param(self, params):
X
xiexionghang 已提交
175 176
        """R
        """
X
xiexionghang 已提交
177 178 179
        scope = params['scope']
        executor = params['executor']
        program = self._build_param['model']['train_program']
X
xiexionghang 已提交
180
        for table_name, table in self._build_param['table'].items():
T
tangwei 已提交
181 182
            fleet._fleet_ptr.pull_dense(scope, table['_meta']._table_id,
                                        table['params'])
X
xiexionghang 已提交
183
        for infernce_item in params['inference_list']:
T
tangwei 已提交
184 185 186 187 188
            params_name_list = self.inference_params(infernce_item[
                'layer_name'])
            params_var_list = [
                program.global_block().var(i) for i in params_name_list
            ]
X
xiexionghang 已提交
189 190 191
            params_file_name = infernce_item['save_file_name']
            with fluid.scope_guard(scope):
                if params['save_combine']:
X
xiexionghang 已提交
192
                    fluid.io.save_vars(executor, "./", \
T
tangwei 已提交
193
                                       program, vars=params_var_list, filename=params_file_name)
X
xiexionghang 已提交
194
                else:
T
tangwei 已提交
195 196 197 198 199
                    fluid.io.save_vars(
                        executor,
                        params_file_name,
                        program,
                        vars=params_var_list)
T
tangwei 已提交
200 201 202 203 204 205 206 207 208 209 210 211 212 213

    def inference_params(self, inference_layer):
        """
        get params name for inference_layer
        Args:
            inference_layer(str): layer for inference
        Return:
            params(list): params name list that for inference layer
        """
        layer = inference_layer
        if layer in self._inference_meta['params']:
            return self._inference_meta['params'][layer]

        self._inference_meta['params'][layer] = []
T
tangwei 已提交
214 215
        self._inference_meta['dependency'][layer] = self.get_dependency(
            self._build_param['inner_layer'], layer)
T
tangwei 已提交
216 217 218
        for node in self._build_nodes['layer']:
            if node['name'] not in self._inference_meta['dependency'][layer]:
                continue
T
tangwei 已提交
219 220
            if 'inference_param' in self._build_param['layer_extend'][node[
                    'name']]:
T
tangwei 已提交
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
                self._inference_meta['params'][layer] += \
                    self._build_param['layer_extend'][node['name']]['inference_param']['params']
        return self._inference_meta['params'][layer]

    def get_dependency(self, layer_graph, dest_layer):
        """
        get model of dest_layer depends on
        Args:
            layer_graph(dict) : all model in graph
        Return:
            depend_layers(list) : sub-graph model for calculate dest_layer
        """
        dependency_list = []
        if dest_layer in layer_graph:
            dependencys = copy.deepcopy(layer_graph[dest_layer]['input'])
            dependency_list = copy.deepcopy(dependencys)
            for dependency in dependencys:
T
tangwei 已提交
238 239
                dependency_list = dependency_list + self.get_dependency(
                    layer_graph, dependency)
T
tangwei 已提交
240
        return list(set(dependency_list))