提交 f97daa3d 编写于 作者: C ceci3

update block

上级 aa7e3b37
...@@ -22,8 +22,9 @@ from paddle.fluid.param_attr import ParamAttr ...@@ -22,8 +22,9 @@ from paddle.fluid.param_attr import ParamAttr
from .search_space_base import SearchSpaceBase from .search_space_base import SearchSpaceBase
from .base_layer import conv_bn_layer from .base_layer import conv_bn_layer
from .search_space_registry import SEARCHSPACE from .search_space_registry import SEARCHSPACE
from .utils import compute_downsample_num
__all__ = ["MobileNetV2BlockSpace"] __all__ = ["MobileNetV1BlockSpace", "MobileNetV2BlockSpace"]
@SEARCHSPACE.register @SEARCHSPACE.register
...@@ -36,44 +37,42 @@ class MobileNetV2BlockSpace(SearchSpaceBase): ...@@ -36,44 +37,42 @@ class MobileNetV2BlockSpace(SearchSpaceBase):
scale=1.0): scale=1.0):
super(MobileNetV2BlockSpace, self).__init__(input_size, output_size, super(MobileNetV2BlockSpace, self).__init__(input_size, output_size,
block_num, block_mask) block_num, block_mask)
self.filter_num1 = np.array([3, 4, 8, 12, 16, 24, 32, 48])
self.filter_num1 = np.array([3, 4, 8, 12, 16, 24, 32, 48]) #8 # use input_size and output_size to compute self.downsample_num
self.filter_num2 = np.array([8, 12, 16, 24, 32, 48, 64, 80]) #8 self.downsample_num = compute_downsample_num(self.input_size, self.output_size)
self.filter_num3 = np.array([16, 24, 32, 48, 64, 80, 96, 128]) #8 if self.block_num != None:
self.filter_num4 = np.array( assert self.downsample_num <= self.block_num, 'downsample numeber must be LESS THAN OR EQUAL TO block_num, but NOW: downsample numeber is {}, block_num is {}'.format(self.downsample_num, self.block_num)
[24, 32, 48, 64, 80, 96, 128, 144, 160, 192]) #10
self.filter_num5 = np.array( # self.filter_num means channel number
[32, 48, 64, 80, 96, 128, 144, 160, 192, 224]) #10 self.filter_num = np.array([3, 4, 8, 12, 16, 24, 32, 48, 64, 80, 96, 128, 144, 160, 192, 224, 256, 320, 384, 512]) # 20
self.filter_num6 = np.array(
[64, 80, 96, 128, 144, 160, 192, 224, 256, 320, 384, 512]) #12
# self.k_size means kernel size # self.k_size means kernel size
self.k_size = np.array([3, 5]) #2 self.k_size = np.array([3, 5]) #2
# self.multiply means expansion_factor of each _inverted_residual_unit # self.multiply means expansion_factor of each _inverted_residual_unit
self.multiply = np.array([1, 2, 3, 4, 6]) #5 self.multiply = np.array([1, 2, 3, 4, 5, 6]) #6
# self.repeat means repeat_num _inverted_residual_unit in each _invresi_blocks # self.repeat means repeat_num _inverted_residual_unit in each _invresi_blocks
self.repeat = np.array([1, 2, 3, 4, 5, 6]) #6 self.repeat = np.array([1, 2, 3, 4, 5, 6]) #6
self.scale = scale self.scale = scale
def init_tokens(self): def init_tokens(self):
return [0] * (len(self.block_mask) * 4) if self.block_mask != None:
return [0] * (len(self.block_mask) * 4)
else:
return [0] * (self.block_num * 4)
def range_table(self): def range_table(self):
range_table_base = [] range_table_base = []
if self.block_mask != None: if self.block_mask != None:
for i in range(len(self.block_mask)): for i in range(len(self.block_mask)):
filter_num = self.__dict__['filter_num{}'.format(i + 1 if i < 6
else 6)]
range_table_base.append(len(self.multiply)) range_table_base.append(len(self.multiply))
range_table_base.append(len(filter_num)) range_table_base.append(len(self.filter_num))
range_table_base.append(len(self.repeat))
range_table_base.append(len(self.k_size))
else:
for i in range(block_num):
range_table_base.append(len(self.multiply))
range_table_base.append(len(self.filter_num))
range_table_base.append(len(self.repeat)) range_table_base.append(len(self.repeat))
range_table_base.append(len(self.k_size)) range_table_base.append(len(self.k_size))
#[len(self.multiply), len(self.filter_num1), len(self.repeat), len(self.k_size),
# len(self.multiply), len(self.filter_num1), len(self.repeat), len(self.k_size),
# len(self.multiply), len(self.filter_num2), len(self.repeat), len(self.k_size),
# len(self.multiply), len(self.filter_num3), len(self.repeat), len(self.k_size),
# len(self.multiply), len(self.filter_num4), len(self.repeat), len(self.k_size),
# len(self.multiply), len(self.filter_num5), len(self.repeat), len(self.k_size),
# len(self.multiply), len(self.filter_num6), len(self.repeat), len(self.k_size)]
return range_table_base return range_table_base
def token2arch(self, tokens=None): def token2arch(self, tokens=None):
...@@ -81,62 +80,44 @@ class MobileNetV2BlockSpace(SearchSpaceBase): ...@@ -81,62 +80,44 @@ class MobileNetV2BlockSpace(SearchSpaceBase):
return mobilenetv2 net_arch function return mobilenetv2 net_arch function
""" """
if tokens is None: if tokens == None:
tokens = self.init_tokens() tokens = self.init_tokens()
print(tokens)
print(len(tokens)) self.bottleneck_params_list = []
if self.block_mask != None:
bottleneck_params_list = []
if self.block_mask == None:
if self.block_num >= 1:
bottleneck_params_list.append(
(1, self.head_num[tokens[0]], 1, 1, 3))
if self.block_num >= 2:
bottleneck_params_list.append(
(self.multiply[tokens[1]], self.filter_num1[tokens[2]],
self.repeat[tokens[3]], 2, self.k_size[tokens[4]]))
if self.block_num >= 3:
bottleneck_params_list.append(
(self.multiply[tokens[5]], self.filter_num1[tokens[6]],
self.repeat[tokens[7]], 2, self.k_size[tokens[8]]))
if self.block_num >= 4:
bottleneck_params_list.append(
(self.multiply[tokens[9]], self.filter_num2[tokens[10]],
self.repeat[tokens[11]], 2, self.k_size[tokens[12]]))
if self.block_num >= 5:
bottleneck_params_list.append(
(self.multiply[tokens[13]], self.filter_num3[tokens[14]],
self.repeat[tokens[15]], 2, self.k_size[tokens[16]]))
bottleneck_params_list.append(
(self.multiply[tokens[17]], self.filter_num4[tokens[18]],
self.repeat[tokens[19]], 1, self.k_size[tokens[20]]))
if self.block_num >= 6:
bottleneck_params_list.append(
(self.multiply[tokens[21]], self.filter_num5[tokens[22]],
self.repeat[tokens[23]], 2, self.k_size[tokens[24]]))
bottleneck_params_list.append(
(self.multiply[tokens[25]], self.filter_num6[tokens[26]],
self.repeat[tokens[27]], 1, self.k_size[tokens[28]]))
else:
for i in range(len(self.block_mask)): for i in range(len(self.block_mask)):
filter_num = self.__dict__['filter_num{}'.format(i + 1 if i < 6 self.bottleneck_params_list.append(
else 6)]
bottleneck_params_list.append(
(self.multiply[tokens[i * 4]], (self.multiply[tokens[i * 4]],
filter_num[tokens[i * 4 + 1]], self.filter_num[tokens[i * 4 + 1]],
self.repeat[tokens[i * 4 + 2]], 2 self.repeat[tokens[i * 4 + 2]], 2
if self.block_mask[i] == 1 else 1, if self.block_mask[i] == 1 else 1,
self.k_size[tokens[i * 4 + 3]])) self.k_size[tokens[i * 4 + 3]]))
else:
repeat_num = 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):
self.bottleneck_params_list.append(self.mutiply[tokens[i * 4], self.filter_num[tokens[i * 4 + 1]],
self.repeat[tokens[i * 4 + 2]], 2, self.k_size[tokens[i * 4 + 3]])
def net_arch(input): ### if block_num / downsample_num > 1, add (block_num / downsample_num) times stride=1 block
for k in range(repeat_num - 1):
kk = k * self.downsample_num + i
self.bottleneck_params_list.append(self.mutiply[tokens[kk * 4], self.filter_num[tokens[kk * 4 + 1]],
self.repeat[tokens[kk * 4 + 2]], 1, self.k_size[tokens[kk * 4 + 3]])
if self.downsample_num - i <= num_minus:
j = self.downsample_num * repeat_num + i
self.bottleneck_params_list.append(self.mutiply[tokens[j * 4], self.filter_num[tokens[j * 4 + 1]],
self.repeat[tokens[j * 4 + 2]], 1, self.k_size[tokens[j * 4 + 3]])
def net_arch(input, return_mid_layer=False):
# all padding is 'SAME' in the conv2d, can compute the actual padding automatic. # all padding is 'SAME' in the conv2d, can compute the actual padding automatic.
# bottleneck sequences # bottleneck sequences
i = 1
in_c = int(32 * self.scale) in_c = int(32 * self.scale)
for layer_setting in bottleneck_params_list: for i, layer_setting in enumerate(self.bottleneck_params_list):
t, c, n, s, k = layer_setting t, c, n, s, k = layer_setting
i += 1 input, depthwise_conv = self._invresi_blocks(
input = self._invresi_blocks(
input=input, input=input,
in_c=in_c, in_c=in_c,
t=t, t=t,
...@@ -144,10 +125,13 @@ class MobileNetV2BlockSpace(SearchSpaceBase): ...@@ -144,10 +125,13 @@ class MobileNetV2BlockSpace(SearchSpaceBase):
n=n, n=n,
s=s, s=s,
k=k, k=k,
name='mobilenetv2_conv' + str(i)) name='mobilenetv2_conv' + str(i+1))
in_c = int(c * self.scale) in_c = int(c * self.scale)
return input if return_mid_layer:
return input, depthwise_conv
else:
return input,
return net_arch return net_arch
...@@ -207,6 +191,8 @@ class MobileNetV2BlockSpace(SearchSpaceBase): ...@@ -207,6 +191,8 @@ class MobileNetV2BlockSpace(SearchSpaceBase):
name=name + '_dwise', name=name + '_dwise',
use_cudnn=False) use_cudnn=False)
depthwise_output = bottleneck_conv
linear_out = conv_bn_layer( linear_out = conv_bn_layer(
input=bottleneck_conv, input=bottleneck_conv,
num_filters=num_filters, num_filters=num_filters,
...@@ -219,7 +205,7 @@ class MobileNetV2BlockSpace(SearchSpaceBase): ...@@ -219,7 +205,7 @@ class MobileNetV2BlockSpace(SearchSpaceBase):
out = linear_out out = linear_out
if ifshortcut: if ifshortcut:
out = self._shortcut(input=input, data_residual=out) out = self._shortcut(input=input, data_residual=out)
return out return out, depthwise_output
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. """Build inverted residual blocks.
...@@ -235,7 +221,7 @@ class MobileNetV2BlockSpace(SearchSpaceBase): ...@@ -235,7 +221,7 @@ class MobileNetV2BlockSpace(SearchSpaceBase):
Returns: Returns:
Variable, layers output. Variable, layers output.
""" """
first_block = self._inverted_residual_unit( first_block, depthwise_output = self._inverted_residual_unit(
input=input, input=input,
num_in_filter=in_c, num_in_filter=in_c,
num_filters=c, num_filters=c,
...@@ -249,7 +235,7 @@ class MobileNetV2BlockSpace(SearchSpaceBase): ...@@ -249,7 +235,7 @@ class MobileNetV2BlockSpace(SearchSpaceBase):
last_c = c last_c = c
for i in range(1, n): for i in range(1, n):
last_residual_block = self._inverted_residual_unit( last_residual_block, depthwise_output = self._inverted_residual_unit(
input=last_residual_block, input=last_residual_block,
num_in_filter=last_c, num_in_filter=last_c,
num_filters=c, num_filters=c,
...@@ -258,4 +244,113 @@ class MobileNetV2BlockSpace(SearchSpaceBase): ...@@ -258,4 +244,113 @@ class MobileNetV2BlockSpace(SearchSpaceBase):
filter_size=k, filter_size=k,
expansion_factor=t, expansion_factor=t,
name=name + '_' + str(i + 1)) name=name + '_' + str(i + 1))
return last_residual_block return last_residual_block, depthwise_output
@SEARCHSPACE.register
class MobileNetV1BlockSpace(SearchSpaceBase):
def __init__(self, input_size, output_size, block_num, block_mask=None, scale=1.0):
super(MobileNetV1BlockSpace, self).__init__(input_size, output_size, block_num, block_mask)
# use input_size and output_size to compute self.downsample_num
self.downsample_num = compute_downsample_num(self.input_size, self.output_size)
if self.block_num != None:
assert self.downsample_num <= self.block_num, 'downsample numeber must be LESS THAN OR EQUAL TO block_num, but NOW: downsample numeber is {}, block_num is {}'.format(self.downsample_num, self.block_num)
# self.filter_num means channel number
self.filter_num = np.array([3, 4, 8, 12, 16, 24, 32, 48, 64, 80, 96, 128, 144, 160, 192, 224, 256, 320, 384, 512, 576, 640, 768, 1024, 1048])
self.k_size = np.array([3, 5])
self.scale = scale
def init_tokens(self):
if self.block_mask != None:
return [0] * (len(self.block_mask) * 3)
else:
return [0] * (self.block_num * 3)
def range_table(self):
range_table_base = []
if self.block_mask != None:
for i in range(len(self.block_mask)):
range_table_base.append(len(self.filter_num))
range_table_base.append(len(self.filter_num))
range_table_base.append(len(self.k_size))
else:
for i in range(self.block_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))
return range_table_base
def token2arch(self, tokens=None):
if tokens == None:
tokens = self.init_tokens()
self.bottleneck_param_list = []
if self.block_mask != None
for i in range(len(self.block_mask)):
self.bottleneck_params_list.append(self.filter_num[tokens[i * 3]], self.filter_num[tokens[i * 3 + 1]], 2 if self.block_mask[i] == 1 else 1, self.k_size[tokens[i * 3 + 2])
else:
repeat_num = self.block_num / self.downsample_num
num_minus = self.block_num % self.downsample_num
for i in range(self.block_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]], self.filter_num[tokens[i * 3 + 1]], 2, self.k_size[tokens[i * 3 + 2])
### if block_num / downsample_num > 1, add (block_num / downsample_num) times stride=1 block
for k in range(repeat_num - 1):
kk = k * self.downsample_num + i
self.bottleneck_params_list.append(self.filter_num[tokens[kk * 3], self.filter_num[tokens[kk * 3 + 1]],
1, self.k_size[tokens[kk * 3 + 2]])
if self.downsample_num - i <= num_minus:
j = self.downsample_num * repeat_num + i
self.bottleneck_params_list.append(self.filter_num[tokens[j * 3], self.filter_num[tokens[j * 3 + 1]],
1, self.k_size[tokens[j * 3 + 2]])
def net_arch(input, return_mid_layer=False):
def net_arch(input):
for i, layer_setting in enumerate(self.bottleneck_params_list):
filter_num1, filter_num2, stride, kernel_size = layer_setting
input = self._depthwise_separable(
input=input,
num_filters1=filter_num1,
num_filters2=filter_num2,
num_groups=filter_num1,
stride=stride,
scale=self.scale,
kernel_size=kernel_size,
name='mobilenetv1_{}'.format(str(i + 1)))
return input
return net_arch
def _depthwise_separable(self,
input,
num_filters1,
num_filters2,
num_groups,
stride,
scale,
kernel_size,
name=None):
depthwise_conv = conv_bn_layer(
input=input,
filter_size=kernel_size,
num_filters=int(num_filters1 * scale),
stride=stride,
num_groups=int(num_groups * scale),
use_cudnn=False,
name=name + '_dw')
pointwise_conv = conv_bn_layer(
input=depthwise_conv,
filter_size=1,
num_filters=int(num_filters2 * scale),
stride=1,
name=name + '_sep')
return pointwise_conv
...@@ -24,6 +24,15 @@ class SearchSpaceBase(object): ...@@ -24,6 +24,15 @@ class SearchSpaceBase(object):
self.output_size = output_size self.output_size = output_size
self.block_num = block_num self.block_num = block_num
self.block_mask = block_mask self.block_mask = block_mask
if self.block_mask != None:
assert isinstance(self.block_mask,
list), 'Block_mask must be a list.'
print(
"If block_mask is NOT None, we will use block_mask as major configs!"
)
self.block_num = None
if self.block_mask == None and self.block_num == None:
print("block_mask and block num can NOT be None at the same time!")
def init_tokens(self): def init_tokens(self):
"""Get init tokens in search space. """Get init tokens in search space.
......
import math
def compute_downsample_num(input_size, output_size):
downsample_num = 0
while input_size > output_size:
input_size = math.ceil(float(input_size) / 2.0)
downsample_num += 1
if input_size != output_size:
raise NotImplementedError('output_size must can downsample by input_size!!!')
return downsample_num
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册