From 9fdb60544a7f7df56db4dbcb71f990c90316e3e3 Mon Sep 17 00:00:00 2001 From: ceci3 <592712189@qq.com> Date: Mon, 11 Nov 2019 03:22:55 +0000 Subject: [PATCH] add multi search_space support --- .../nas/search_space/combine_search_space.py | 94 +++++++++++++++++++ paddleslim/nas/search_space/mobilenetv2.py | 31 +++--- .../nas/search_space/search_space_base.py | 2 +- .../nas/search_space/search_space_factory.py | 17 +--- 4 files changed, 118 insertions(+), 26 deletions(-) create mode 100644 paddleslim/nas/search_space/combine_search_space.py diff --git a/paddleslim/nas/search_space/combine_search_space.py b/paddleslim/nas/search_space/combine_search_space.py new file mode 100644 index 00000000..98b32f02 --- /dev/null +++ b/paddleslim/nas/search_space/combine_search_space.py @@ -0,0 +1,94 @@ +# 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 numpy as np +import paddle.fluid as fluid +from paddle.fluid.param_attr import ParamAttr +from .search_space_base import SearchSpaceBase +from .search_space_registry import SEARCHSPACE +from .base_layer import conv_bn_layer + +__all__ = ["CombineSearchSpace"] + +class CombineSearchSpace(object): + """ + Combine Search Space. + Args: + configs(list): multi config. + """ + def __init__(self, config_lists): + self.lens = len(config_lists) + self.spaces = [] + for config_list in config_lists: + key, config = config_list + self.spaces.append(self._get_single_search_space(key, config)) + + def _get_single_search_space(self, key, config): + """ + get specific model space based on key and config. + + Args: + key(str): model space name. + config(dict): basic config information. + return: + model space(class) + """ + cls = SEARCHSPACE.get(key) + space = cls(config['input_size'], config['output_size'], + config['block_num']) + + return space + + + def init_tokens(self): + """ + Combine init tokens. + """ + tokens = [] + self.token = [] + for space in self.spaces: + tokens.extend(space.init_tokens()) + self.token.append(space.init_tokens()) + return tokens + + def range_table(self): + """ + Combine range table. + """ + range_tables = [] + for space in self.spaces: + range_tables.extend(space.range_table()) + return range_tables + + def token2arch(self, tokens=None): + """ + Combine model arch + """ + if tokens is None: + self.init_tokens() + + model_archs = [] + for space, token in zip(self.spaces, self.token): + model_archs.append(space.token2arch(token)) + + def net_arch(input): + for model_arch in model_archs: + input = model_arch(input) + return input + + return net_arch diff --git a/paddleslim/nas/search_space/mobilenetv2.py b/paddleslim/nas/search_space/mobilenetv2.py index 270da2b1..2c5fa998 100644 --- a/paddleslim/nas/search_space/mobilenetv2.py +++ b/paddleslim/nas/search_space/mobilenetv2.py @@ -52,6 +52,7 @@ class MobileNetV2Space(SearchSpaceBase): self.scale = scale self.class_dim = class_dim + def init_tokens(self): """ The initial token send to controller. @@ -60,7 +61,7 @@ class MobileNetV2Space(SearchSpaceBase): """ # original MobileNetV2 # yapf: disable - return [4, # 1, 16, 1 + init_token_base = [4, # 1, 16, 1 4, 5, 1, 0, # 6, 24, 1 4, 5, 1, 0, # 6, 24, 2 4, 4, 2, 0, # 6, 32, 3 @@ -69,6 +70,7 @@ class MobileNetV2Space(SearchSpaceBase): 4, 7, 2, 0, # 6, 160, 3 4, 9, 0, 0] # 6, 320, 1 # yapf: enable + return init_token_base#[:self.tokens_lens] def range_table(self): """ @@ -76,7 +78,7 @@ class MobileNetV2Space(SearchSpaceBase): """ # head_num + 7 * [multiple(expansion_factor), filter_num, repeat, kernel_size] # yapf: disable - return [7, + range_table_base = [7, 5, 8, 6, 2, 5, 8, 6, 2, 5, 8, 6, 2, @@ -85,6 +87,7 @@ class MobileNetV2Space(SearchSpaceBase): 5, 10, 6, 2, 5, 12, 6, 2] # yapf: enable + return range_table_base#[:self.tokens_lens] def token2arch(self, tokens=None): """ @@ -127,6 +130,8 @@ class MobileNetV2Space(SearchSpaceBase): else: break + self.tokens_lens = 1 + (len(bottleneck_params_list) - 1) * 4 + def net_arch(input): #conv1 # all padding is 'SAME' in the conv2d, can compute the actual padding automatic. @@ -137,7 +142,7 @@ class MobileNetV2Space(SearchSpaceBase): stride=2, padding='SAME', act='relu6', - name='conv1_1') + name='mobilenetv2_conv1_1') # bottleneck sequences i = 1 @@ -145,7 +150,7 @@ class MobileNetV2Space(SearchSpaceBase): for layer_setting in bottleneck_params_list: t, c, n, s, k = layer_setting i += 1 - input = self.invresi_blocks( + input = self._invresi_blocks( input=input, in_c=in_c, t=t, @@ -153,7 +158,7 @@ class MobileNetV2Space(SearchSpaceBase): n=n, s=s, k=k, - name='conv' + str(i)) + name='mobilenetv2_conv' + str(i)) in_c = int(c * self.scale) # if output_size is 1, add fc layer in the end @@ -161,8 +166,8 @@ class MobileNetV2Space(SearchSpaceBase): input = fluid.layers.fc( input=input, size=self.class_dim, - param_attr=ParamAttr(name='fc10_weights'), - bias_attr=ParamAttr(name='fc10_offset')) + param_attr=ParamAttr(name='mobilenetv2_fc_weights'), + bias_attr=ParamAttr(name='mobilenetv2_fc_offset')) else: assert self.output_size == input.shape[2], \ ("output_size must EQUAL to input_size / (2^block_num)." @@ -173,7 +178,7 @@ class MobileNetV2Space(SearchSpaceBase): return net_arch - def shortcut(self, input, data_residual): + def _shortcut(self, input, data_residual): """Build shortcut layer. Args: input(Variable): input. @@ -183,7 +188,7 @@ class MobileNetV2Space(SearchSpaceBase): """ return fluid.layers.elementwise_add(input, data_residual) - def inverted_residual_unit(self, + def _inverted_residual_unit(self, input, num_in_filter, num_filters, @@ -240,10 +245,10 @@ class MobileNetV2Space(SearchSpaceBase): name=name + '_linear') out = linear_out if ifshortcut: - out = self.shortcut(input=input, data_residual=out) + out = self._shortcut(input=input, data_residual=out) return out - def invresi_blocks(self, input, in_c, t, c, n, s, k, name=None): + def _invresi_blocks(self, input, in_c, t, c, n, s, k, name=None): """Build inverted residual blocks. Args: input: Variable, input. @@ -257,7 +262,7 @@ class MobileNetV2Space(SearchSpaceBase): Returns: Variable, layers output. """ - first_block = self.inverted_residual_unit( + first_block = self._inverted_residual_unit( input=input, num_in_filter=in_c, num_filters=c, @@ -271,7 +276,7 @@ class MobileNetV2Space(SearchSpaceBase): last_c = c for i in range(1, n): - last_residual_block = self.inverted_residual_unit( + last_residual_block = self._inverted_residual_unit( input=last_residual_block, num_in_filter=last_c, num_filters=c, diff --git a/paddleslim/nas/search_space/search_space_base.py b/paddleslim/nas/search_space/search_space_base.py index a68ec63a..bb1ce0f8 100644 --- a/paddleslim/nas/search_space/search_space_base.py +++ b/paddleslim/nas/search_space/search_space_base.py @@ -39,6 +39,6 @@ class SearchSpaceBase(object): Args: tokens(list): The tokens which represent a network. Return: - list + model arch """ raise NotImplementedError('Abstract method.') diff --git a/paddleslim/nas/search_space/search_space_factory.py b/paddleslim/nas/search_space/search_space_factory.py index 11d8377d..2fc0be83 100644 --- a/paddleslim/nas/search_space/search_space_factory.py +++ b/paddleslim/nas/search_space/search_space_factory.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from search_space_registry import SEARCHSPACE +from .combine_search_space import CombineSearchSpace __all__ = ["SearchSpaceFactory"] @@ -21,18 +21,11 @@ class SearchSpaceFactory(object): def __init__(self): pass - def get_search_space(self, key, config): + def get_search_space(self, config_lists): """ - get specific model space based on key and config. + get model spaces based on list(key, config). - Args: - key(str): model space name. - config(dict): basic config information. - return: - model space(class) """ - cls = SEARCHSPACE.get(key) - space = cls(config['input_size'], config['output_size'], - config['block_num']) + assert isinstance(config_lists, list), "configs must be a list" - return space + return CombineSearchSpace(config_lists) -- GitLab