From faa7351318a519a8188b6e05257461dce3f8c9aa Mon Sep 17 00:00:00 2001 From: ceci3 <592712189@qq.com> Date: Thu, 5 Dec 2019 11:48:26 +0000 Subject: [PATCH] update block --- .../nas/search_space/combine_search_space.py | 6 +- .../nas/search_space/inception_block.py | 13 +- .../nas/search_space/mobilenet_block.py | 23 ++-- paddleslim/nas/search_space/mobilenetv1.py | 10 +- paddleslim/nas/search_space/mobilenetv2.py | 2 +- paddleslim/nas/search_space/resnet_block.py | 112 ++++++++++++------ 6 files changed, 108 insertions(+), 58 deletions(-) diff --git a/paddleslim/nas/search_space/combine_search_space.py b/paddleslim/nas/search_space/combine_search_space.py index 8e18060b..7bb66c00 100644 --- a/paddleslim/nas/search_space/combine_search_space.py +++ b/paddleslim/nas/search_space/combine_search_space.py @@ -87,9 +87,9 @@ class CombineSearchSpace(object): block_num = config['block_num'] if 'block_num' in config else None if 'Block' in cls.__name__: - if block_mask == None and (self.block_num == None or - self.input_size == None or - self.output_size == None): + if block_mask == None and (block_num == None or + input_size == None or + output_size == None): raise NotImplementedError( "block_mask or (block num and input_size and output_size) can NOT be None at the same time in Block SPACE!" ) diff --git a/paddleslim/nas/search_space/inception_block.py b/paddleslim/nas/search_space/inception_block.py index 4a3bfcfa..6a49f384 100644 --- a/paddleslim/nas/search_space/inception_block.py +++ b/paddleslim/nas/search_space/inception_block.py @@ -22,6 +22,7 @@ from paddle.fluid.param_attr import ParamAttr from .search_space_base import SearchSpaceBase from .base_layer import conv_bn_layer from .search_space_registry import SEARCHSPACE +from .utils import compute_downsample_num __all__ = ["InceptionABlockSpace", "InceptionCBlockSpace"] ### TODO add asymmetric kernel of conv when paddle-lite support @@ -70,7 +71,7 @@ class InceptionABlockSpace(SearchSpaceBase): if self.block_mask != None: range_table_length = len(self.block_mask) else: - range_table_length = self.block_mum + range_table_length = self.block_num for i in range(range_table_length): range_table_base.append(len(self.filter_num)) @@ -107,7 +108,7 @@ class InceptionABlockSpace(SearchSpaceBase): self.k_size[tokens[i * 9 + 7]], 2 if self.block_mask == 1 else 1, self.pool_type[tokens[i * 9 + 8]])) else: - repeat_num = self.block_num / self.downsample_num + repeat_num = int(self.block_num / self.downsample_num) num_minus = self.block_num % self.downsample_num ### if block_num > downsample_num, add stride=1 block at last (block_num-downsample_num) layers for i in range(self.downsample_num): @@ -136,7 +137,7 @@ class InceptionABlockSpace(SearchSpaceBase): self.pool_type[tokens[kk * 9 + 8]])) if self.downsample_num - i <= num_minus: - j = self.downsample_num * repeat_num + i + j = self.downsample_num * (repeat_num - 1) + i self.bottleneck_params_list.append( (self.filter_num[tokens[j * 9]], self.filter_num[tokens[j * 9 + 1]], @@ -304,7 +305,7 @@ class InceptionCBlockSpace(SearchSpaceBase): if self.block_mask != None: range_table_length = len(self.block_mask) else: - range_table_length = self.block_mum + range_table_length = self.block_num for i in range(range_table_length): range_table_base.append(len(self.filter_num)) @@ -343,7 +344,7 @@ class InceptionCBlockSpace(SearchSpaceBase): self.k_size[tokens[i * 11 + 9]], 2 if self.block_mask == 1 else 1, self.pool_type[tokens[i * 11 + 10]])) else: - repeat_num = self.block_num / self.downsample_num + repeat_num = int(self.block_num / self.downsample_num) num_minus = self.block_num % self.downsample_num ### if block_num > downsample_num, add stride=1 block at last (block_num-downsample_num) layers for i in range(self.downsample_num): @@ -376,7 +377,7 @@ class InceptionCBlockSpace(SearchSpaceBase): self.pool_type[tokens[kk * 11 + 10]])) if self.downsample_num - i <= num_minus: - j = self.downsample_num * repeat_num + i + j = self.downsample_num * (repeat_num - 1) + i self.bottleneck_params_list.append( (self.filter_num[tokens[j * 11]], self.filter_num[tokens[j * 11 + 1]], diff --git a/paddleslim/nas/search_space/mobilenet_block.py b/paddleslim/nas/search_space/mobilenet_block.py index 39438cd1..9a1a8e67 100644 --- a/paddleslim/nas/search_space/mobilenet_block.py +++ b/paddleslim/nas/search_space/mobilenet_block.py @@ -70,7 +70,7 @@ class MobileNetV2BlockSpace(SearchSpaceBase): if self.block_mask != None: range_table_length = len(self.block_mask) else: - range_table_length = self.block_mum + range_table_length = self.block_num for i in range(range_table_length): range_table_base.append(len(self.multiply)) @@ -98,7 +98,7 @@ class MobileNetV2BlockSpace(SearchSpaceBase): if self.block_mask[i] == 1 else 1, self.k_size[tokens[i * 4 + 3]])) else: - repeat_num = self.block_num / self.downsample_num + repeat_num = int(self.block_num / self.downsample_num) num_minus = self.block_num % self.downsample_num ### if block_num > downsample_num, add stride=1 block at last (block_num-downsample_num) layers for i in range(self.downsample_num): @@ -118,7 +118,7 @@ class MobileNetV2BlockSpace(SearchSpaceBase): self.k_size[tokens[kk * 4 + 3]])) if self.downsample_num - i <= num_minus: - j = self.downsample_num * repeat_num + i + j = self.downsample_num * (repeat_num - 1) + i self.bottleneck_params_list.append( (self.multiply[tokens[j * 4]], self.filter_num[tokens[j * 4 + 1]], @@ -343,9 +343,9 @@ class MobileNetV1BlockSpace(SearchSpaceBase): if self.block_mask[i] == 1 else 1, self.k_size[tokens[i * 3 + 2]])) else: - repeat_num = self.block_num / self.downsample_num + repeat_num = int(self.block_num / self.downsample_num) num_minus = self.block_num % self.downsample_num - for i in range(self.block_num): + for i in range(self.downsample_num): ### if block_num > downsample_num, add stride=1 block at last (block_num-downsample_num) layers self.bottleneck_params_list.append( (self.filter_num[tokens[i * 3]], @@ -361,7 +361,7 @@ class MobileNetV1BlockSpace(SearchSpaceBase): self.k_size[tokens[kk * 3 + 2]])) if self.downsample_num - i <= num_minus: - j = self.downsample_num * repeat_num + i + j = self.downsample_num * (repeat_num - 1) + i self.bottleneck_params_list.append( (self.filter_num[tokens[j * 3]], self.filter_num[tokens[j * 3 + 1]], 1, @@ -399,7 +399,7 @@ class MobileNetV1BlockSpace(SearchSpaceBase): if return_mid_layer: return input, mid_layer else: - return input + return input, return net_arch @@ -412,10 +412,17 @@ class MobileNetV1BlockSpace(SearchSpaceBase): kernel_size, name=None): num_groups = input.shape[1] + + s_oc = int(num_filters1 * scale) + if s_oc > num_groups: + output_channel = s_oc - (s_oc % num_groups) + else: + output_channel = num_groups + depthwise_conv = conv_bn_layer( input=input, filter_size=kernel_size, - num_filters=int(num_filters1 * scale), + num_filters=output_channel, stride=stride, num_groups=num_groups, use_cudnn=False, diff --git a/paddleslim/nas/search_space/mobilenetv1.py b/paddleslim/nas/search_space/mobilenetv1.py index 8ba45c77..b61166d9 100644 --- a/paddleslim/nas/search_space/mobilenetv1.py +++ b/paddleslim/nas/search_space/mobilenetv1.py @@ -182,7 +182,7 @@ class MobileNetV1Space(SearchSpaceBase): name='mobilenetv1_conv1') layer_count = 1 - for i, layer_setting in enumerate(bottleneck_param_list): + for i, layer_setting in enumerate(self.bottleneck_param_list): filter_num1, filter_num2, stride, kernel_size = layer_setting if stride == 2: layer_count += 1 @@ -225,6 +225,14 @@ class MobileNetV1Space(SearchSpaceBase): scale, kernel_size, name=None): + num_groups = input.shape[1] + + s_oc = int(num_filters1 * scale) + if s_oc > num_groups: + output_channel = s_oc - (s_oc % num_groups) + else: + output_channel = num_groups + depthwise_conv = conv_bn_layer( input=input, filter_size=kernel_size, diff --git a/paddleslim/nas/search_space/mobilenetv2.py b/paddleslim/nas/search_space/mobilenetv2.py index 56272a80..cb50ae63 100644 --- a/paddleslim/nas/search_space/mobilenetv2.py +++ b/paddleslim/nas/search_space/mobilenetv2.py @@ -168,7 +168,7 @@ class MobileNetV2Space(SearchSpaceBase): depthwise_output = None # bottleneck sequences in_c = int(32 * self.scale) - for layer_setting in self.bottleneck_params_list: + for i, layer_setting in enumerate(self.bottleneck_params_list): t, c, n, s, k = layer_setting if s == 2: layer_count += 1 diff --git a/paddleslim/nas/search_space/resnet_block.py b/paddleslim/nas/search_space/resnet_block.py index c9f215d3..f4603c02 100644 --- a/paddleslim/nas/search_space/resnet_block.py +++ b/paddleslim/nas/search_space/resnet_block.py @@ -40,26 +40,29 @@ class ResNetBlockSpace(SearchSpaceBase): self.downsample_num, self.block_num) self.filter_num = np.array( [48, 64, 96, 128, 160, 192, 224, 256, 320, 384, 512, 640]) - ### TODO: use repeat to compute normal cell - #self.repeat = [2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24] + self.repeat = np.array([0, 1, 2]) self.k_size = np.array([3, 5]) def init_tokens(self): if self.block_mask != None: - return [0] * (len(self.block_mask) * 2) + return [0] * (len(self.block_mask) * 6) else: - return [0] * (self.block_num * 2) + return [0] * (self.block_num * 6) def range_table(self): range_table_base = [] if self.block_mask != None: range_table_length = len(self.block_mask) else: - range_table_length = self.block_mum + range_table_length = self.block_num for i in range(range_table_length): + range_table_base.append(len(self.filter_num)) + range_table_base.append(len(self.filter_num)) range_table_base.append(len(self.filter_num)) range_table_base.append(len(self.k_size)) + range_table_base.append(len(self.repeat)) + range_table_base.append(len(self.repeat)) return range_table_base @@ -71,32 +74,52 @@ class ResNetBlockSpace(SearchSpaceBase): if self.block_mask != None: for i in range(len(self.block_mask)): self.bottleneck_params_list.append( - (self.filter_num[tokens[i * 2]], - self.k_size[tokens[i * 2 + 1]], 2 + (self.filter_num[tokens[i * 6]], + self.filter_num[tokens[i * 6 + 1]], + self.filter_num[tokens[i * 6 + 2]], + self.k_size[tokens[i * 6 + 3]], + self.repeat[tokens[i * 6 + 4]], + self.repeat[tokens[i * 6 + 5]], 2 if self.block_mask[i] == 1 else 1)) else: - repeat_num = self.block_num / self.downsample_num + repeat_num = int(self.block_num / self.downsample_num) num_minus = self.block_num % self.downsample_num for i in range(self.downsample_num): self.bottleneck_params_list.append( - self.filter_num[tokens[i * 2]], - self.k_size[tokens[i * 2 + 1]], 2) + (self.filter_num[tokens[i * 6]], + self.filter_num[tokens[i * 6 + 1]], + self.filter_num[tokens[i * 6 + 2]], + self.k_size[tokens[i * 6 + 3]], + self.repeat[tokens[i * 6 + 4]], + self.repeat[tokens[i * 6 + 5]], 2)) for k in range(repeat_num - 1): kk = k * self.downsample_num + i self.bottleneck_params_list.append( - self.filter_num[tokens[kk * 2]], - self.k_size[tokens[kk * 2 + 1]], 1) + (self.filter_num[tokens[kk * 6]], + self.filter_num[tokens[kk * 6 + 1]], + self.filter_num[tokens[kk * 6 + 2]], + self.k_size[tokens[kk * 6 + 3]], + self.repeat[tokens[kk * 6 + 4]], + self.repeat[tokens[kk * 6 + 5]], 1)) if self.downsample_num - i <= num_minus: - j = self.downsample_num * repeat_num + i + j = self.downsample_num * (repeat_num - 1) + i self.bottleneck_params_list.append( - self.filter_num[tokens[j * 2]], - self.k_size[tokens[j * 2 + 1]], 1) + (self.filter_num[tokens[j * 6]], + self.filter_num[tokens[j * 6 + 1]], + self.filter_num[tokens[j * 6 + 2]], + self.k_size[tokens[j * 6 + 3]], + self.repeat[tokens[j * 6 + 4]], + self.repeat[tokens[j * 6 + 5]], 1)) if self.downsample_num == 0 and self.block_num != 0: for i in range(len(self.block_num)): self.bottleneck_params_list.append( - self.filter_num[tokens[i * 2]], - self.k_size[tokens[i * 2 + 1]], 1) + (self.filter_num[tokens[i * 6]], + self.filter_num[tokens[i * 6 + 1]], + self.filter_num[tokens[i * 6 + 2]], + self.k_size[tokens[i * 6 + 3]], + self.repeat[tokens[i * 6 + 4]], + self.repeat[tokens[i * 6 + 5]], 1)) def net_arch(input, return_mid_layer=False, return_block=[]): assert isinstance(return_block, @@ -104,7 +127,7 @@ class ResNetBlockSpace(SearchSpaceBase): layer_count = 0 mid_layer = dict() for i, layer_setting in enumerate(self.bottleneck_params_list): - filter_num, k_size, stride = layer_setting + filter_num1, filter_num2, filter_num3, k_size, repeat1, repeat2, stride = layer_setting if stride == 2: layer_count += 1 if (layer_count - 1) in return_block: @@ -112,8 +135,12 @@ class ResNetBlockSpace(SearchSpaceBase): input = self._bottleneck_block( input=input, - num_filters=filter_num, + num_filters1=filter_num1, + num_filters2=filter_num3, + num_filters3=filter_num3, kernel_size=k_size, + repeat1=repeat1, + repeat2=repeat2, stride=stride, name='resnet' + str(i + 1)) @@ -138,33 +165,40 @@ class ResNetBlockSpace(SearchSpaceBase): def _bottleneck_block(self, input, - num_filters, + num_filters1, + num_filters2, + num_filters3, kernel_size, + repeat1, + repeat2, stride, name=None): - conv0 = conv_bn_layer( + short = self._shortcut(input, num_filters3, stride, name=name) + + for i in range(repeat1): + input = conv_bn_layer( + input=input, + num_filters=num_filters1, + filter_size=1, + stride=1, + act='relu', + name=name + '_bottleneck_conv0_{}'.format(str(i))) + + input = conv_bn_layer( input=input, - num_filters=num_filters, - filter_size=1, - stride=1, - act='relu', - name=name + '_bottleneck_conv0') - conv1 = conv_bn_layer( - input=conv0, - num_filters=num_filters, + num_filters=num_filters2, filter_size=kernel_size, stride=stride, act='relu', name=name + '_bottleneck_conv1') - conv2 = conv_bn_layer( - input=conv1, - num_filters=num_filters * 4, - filter_size=1, - stride=1, - act=None, - name=name + '_bottleneck_conv2') - - short = self._shortcut(input, num_filters * 4, stride, name=name) + for i in range(repeat2): + input = conv_bn_layer( + input=input, + num_filters=num_filters3, + filter_size=1, + stride=1, + act=None, + name=name + '_bottleneck_conv2_{}'.format(str(i))) return fluid.layers.elementwise_add( - x=short, y=conv2, act='relu', name=name + '_bottleneck_add') + x=short, y=input, act='relu', name=name + '_bottleneck_add') -- GitLab