remove the init params in regnet model
parent
70b203574d
commit
a8f164018f
|
@ -0,0 +1,282 @@
|
|||
#copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
|
||||
#
|
||||
#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 math
|
||||
|
||||
import paddle
|
||||
import paddle.fluid as fluid
|
||||
from paddle.fluid.param_attr import ParamAttr
|
||||
import math
|
||||
import numpy as np
|
||||
|
||||
__all__ = ["RegNetX_200MF", "RegNetX_4GF", "RegNetX_32GF", "RegNetY_200MF", "RegNetY_4GF", "RegNetY_32GF"]
|
||||
|
||||
|
||||
class RegNet():
|
||||
def __init__(self, w_a, w_0, w_m, d, group_w, bot_mul, q=8, se_on=False):
|
||||
self.w_a = w_a
|
||||
self.w_0 = w_0
|
||||
self.w_m = w_m
|
||||
self.d = d
|
||||
self.q = q
|
||||
self.group_w = group_w
|
||||
self.bot_mul = bot_mul
|
||||
# Stem type
|
||||
self.stem_type = "simple_stem_in"
|
||||
# Stem width
|
||||
self.stem_w = 32
|
||||
# Block type
|
||||
self.block_type = "res_bottleneck_block"
|
||||
# Stride of each stage
|
||||
self.stride = 2
|
||||
# Squeeze-and-Excitation (RegNetY)
|
||||
self.se_on = se_on
|
||||
self.se_r = 0.25
|
||||
|
||||
def quantize_float(self, f, q):
|
||||
"""Converts a float to closest non-zero int divisible by q."""
|
||||
return int(round(f / q) * q)
|
||||
|
||||
def adjust_ws_gs_comp(self, ws, bms, gs):
|
||||
"""Adjusts the compatibility of widths and groups."""
|
||||
ws_bot = [int(w * b) for w, b in zip(ws, bms)]
|
||||
gs = [min(g, w_bot) for g, w_bot in zip(gs, ws_bot)]
|
||||
ws_bot = [self.quantize_float(w_bot, g) for w_bot, g in zip(ws_bot, gs)]
|
||||
ws = [int(w_bot / b) for w_bot, b in zip(ws_bot, bms)]
|
||||
return ws, gs
|
||||
|
||||
def get_stages_from_blocks(self, ws, rs):
|
||||
"""Gets ws/ds of network at each stage from per block values."""
|
||||
ts = [
|
||||
w != wp or r != rp
|
||||
for w, wp, r, rp in zip(ws + [0], [0] + ws, rs + [0], [0] + rs)
|
||||
]
|
||||
s_ws = [w for w, t in zip(ws, ts[:-1]) if t]
|
||||
s_ds = np.diff([d for d, t in zip(range(len(ts)), ts) if t]).tolist()
|
||||
return s_ws, s_ds
|
||||
|
||||
def generate_regnet(self, w_a, w_0, w_m, d, q=8):
|
||||
"""Generates per block ws from RegNet parameters."""
|
||||
assert w_a >= 0 and w_0 > 0 and w_m > 1 and w_0 % q == 0
|
||||
ws_cont = np.arange(d) * w_a + w_0
|
||||
ks = np.round(np.log(ws_cont / w_0) / np.log(w_m))
|
||||
ws = w_0 * np.power(w_m, ks)
|
||||
ws = np.round(np.divide(ws, q)) * q
|
||||
num_stages, max_stage = len(np.unique(ws)), ks.max() + 1
|
||||
ws, ws_cont = ws.astype(int).tolist(), ws_cont.tolist()
|
||||
return ws, num_stages, max_stage, ws_cont
|
||||
|
||||
def init_weights(self, op_type, filter_size=0, num_channels=0, name=None):
|
||||
if op_type == 'conv':
|
||||
fan_out = num_channels * filter_size * filter_size
|
||||
param_attr = ParamAttr(
|
||||
name=name + "_weights",
|
||||
initializer=fluid.initializer.NormalInitializer(
|
||||
loc=0.0, scale=math.sqrt(2.0 / fan_out)))
|
||||
bias_attr = False
|
||||
elif op_type == 'bn':
|
||||
param_attr = ParamAttr(
|
||||
name=name + "_scale",initializer=fluid.initializer.Constant(0.0))
|
||||
bias_attr = ParamAttr(
|
||||
name=name + "_offset", initializer=fluid.initializer.Constant(0.0))
|
||||
elif op_type == 'final_bn':
|
||||
param_attr = ParamAttr(
|
||||
name=name + "_scale",initializer=fluid.initializer.Constant(1.0))
|
||||
bias_attr = ParamAttr(
|
||||
name=name + "_offset", initializer=fluid.initializer.Constant(0.0))
|
||||
return param_attr, bias_attr
|
||||
|
||||
def net(self, input, class_dim=1000):
|
||||
# Generate RegNet ws per block
|
||||
b_ws, num_s, max_s, ws_cont = self.generate_regnet(self.w_a, self.w_0, self.w_m, self.d, self.q)
|
||||
#print('generate_regnet func done!')
|
||||
#print('b_ws={}, num_stages={}, max_stage={}, ws_cont={}'.format(b_ws, num_s, max_s, ws_cont))
|
||||
# Convert to per stage format
|
||||
ws, ds = self.get_stages_from_blocks(b_ws, b_ws)
|
||||
#print('get_stages_from_blocks func done!')
|
||||
#print('ws={}, ds={}'.format(ws, ds))
|
||||
# Generate group widths and bot muls
|
||||
gws = [self.group_w for _ in range(num_s)]
|
||||
bms = [self.bot_mul for _ in range(num_s)]
|
||||
#print('gws={}'.format(gws))
|
||||
#print('bms={}'.format(bms))
|
||||
# Adjust the compatibility of ws and gws
|
||||
#print('adjust_ws_gs_comp func done!')
|
||||
ws, gws = self.adjust_ws_gs_comp(ws, bms, gws)
|
||||
print('ws={}'.format(ws))
|
||||
print('gws={}'.format(gws))
|
||||
# Use the same stride for each stage
|
||||
ss = [self.stride for _ in range(num_s)]
|
||||
# Use SE for RegNetY
|
||||
se_r = self.se_r
|
||||
|
||||
# Construct the model
|
||||
# Group params by stage
|
||||
stage_params = list(zip(ds, ws, ss, bms, gws))
|
||||
# Construct the stem
|
||||
conv = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=self.stem_w,
|
||||
filter_size=3,
|
||||
stride=2,
|
||||
padding=1,
|
||||
act='relu',
|
||||
name="stem_conv")
|
||||
# Construct the stages
|
||||
for block, (d, w_out, stride, bm, gw) in enumerate(stage_params):
|
||||
for i in range(d):
|
||||
# Stride apply to the first block of the stage
|
||||
b_stride = stride if i == 0 else 1
|
||||
conv_name = 's' + str(block + 1) + '_b' + str(i + 1) #chr(97 + i)
|
||||
conv = self.bottleneck_block(
|
||||
input=conv,
|
||||
num_filters=w_out,
|
||||
stride=b_stride,
|
||||
bm=bm,
|
||||
gw=gw,
|
||||
se_r=self.se_r,
|
||||
name=conv_name)
|
||||
pool = fluid.layers.pool2d(
|
||||
input=conv, pool_type='avg', global_pooling=True)
|
||||
out = fluid.layers.fc(
|
||||
input=pool,
|
||||
size=class_dim,
|
||||
param_attr=ParamAttr(
|
||||
name = "fc_0.w_0",
|
||||
initializer=fluid.initializer.NormalInitializer(loc=0.0, scale=0.01)),
|
||||
bias_attr=ParamAttr(
|
||||
name="fc_0.b_0",
|
||||
initializer=fluid.initializer.Constant(0.0)))
|
||||
return out
|
||||
|
||||
def conv_bn_layer(self,
|
||||
input,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
padding=0,
|
||||
act=None,
|
||||
name=None,
|
||||
final_bn=False):
|
||||
conv = fluid.layers.conv2d(
|
||||
input=input,
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
stride=stride,
|
||||
padding=padding,
|
||||
groups=groups,
|
||||
act=None,
|
||||
name=name + '.conv2d.output.1')
|
||||
bn_name = name + '_bn'
|
||||
|
||||
return fluid.layers.batch_norm(
|
||||
input=conv,
|
||||
act=act,
|
||||
name=bn_name + '.output.1',
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance', )
|
||||
#todo: to check the bn layer's eps and momentum, and relu_inplace
|
||||
|
||||
def shortcut(self, input, ch_out, stride, name):
|
||||
ch_in = input.shape[1]
|
||||
if ch_in != ch_out or stride != 1:
|
||||
return self.conv_bn_layer(input=input, num_filters=ch_out, filter_size=1, stride=stride, padding=0, act=None, name=name)
|
||||
else:
|
||||
return input
|
||||
|
||||
def bottleneck_block(self, input, num_filters, stride, bm, gw, se_r, name):
|
||||
# Compute the bottleneck width
|
||||
w_b = int(round(num_filters * bm))
|
||||
# Compute the number of groups
|
||||
num_gs = w_b // gw
|
||||
conv0 = self.conv_bn_layer(
|
||||
input=input, num_filters=w_b, filter_size=1, stride=1, padding=0, act='relu', name=name+"_branch2a")
|
||||
conv1 = self.conv_bn_layer(
|
||||
input=conv0,
|
||||
num_filters=w_b,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
padding=1,
|
||||
groups=num_gs,
|
||||
act='relu',
|
||||
name=name+"_branch2b")
|
||||
# Squeeze-and-Excitation (SE)
|
||||
if self.se_on:
|
||||
w_se = int(round(input.shape[1] * se_r))
|
||||
conv1 = self.squeeze_excitation(
|
||||
input=conv1,
|
||||
num_channels=w_b,
|
||||
reduction_channels=w_se,
|
||||
name=name+"_branch2se")
|
||||
|
||||
conv2 =self.conv_bn_layer(
|
||||
input=conv1, num_filters=num_filters, filter_size=1, stride=1, padding=0, act=None, name=name+"_branch2c", final_bn=True)
|
||||
|
||||
short = self.shortcut(input, num_filters, stride, name=name + "_branch1")
|
||||
|
||||
return fluid.layers.elementwise_add(x=short, y=conv2, act='relu')
|
||||
|
||||
def squeeze_excitation(self, input, num_channels, reduction_channels, name=None):
|
||||
pool = fluid.layers.pool2d(
|
||||
input=input, pool_size=0, pool_type='avg', global_pooling=True)
|
||||
fan_out = num_channels
|
||||
squeeze = fluid.layers.conv2d(input=pool,
|
||||
num_filters=reduction_channels,
|
||||
filter_size=1,
|
||||
act='relu',
|
||||
param_attr=ParamAttr(
|
||||
initializer=fluid.initializer.NormalInitializer(loc=0.0, scale=math.sqrt(2.0 / fan_out)),
|
||||
name=name+'_sqz_weights'),
|
||||
bias_attr=ParamAttr(name=name+'_sqz_offset'))
|
||||
excitation = fluid.layers.conv2d(input=squeeze,
|
||||
num_filters=num_channels,
|
||||
filter_size=1,
|
||||
act='sigmoid',
|
||||
param_attr=ParamAttr(
|
||||
initializer=fluid.initializer.NormalInitializer(loc=0.0, scale=math.sqrt(2.0 / fan_out)),
|
||||
name=name+'_exc_weights'),
|
||||
bias_attr=ParamAttr(name=name+'_exc_offset'))
|
||||
scale = fluid.layers.elementwise_mul(x=input, y=excitation, axis=0)
|
||||
return scale
|
||||
|
||||
|
||||
|
||||
def RegNetX_200MF():
|
||||
model = RegNet(w_a=36.44, w_0=24, w_m=2.49, d=13, group_w=8, bot_mul=1.0, q=8)
|
||||
return model
|
||||
|
||||
def RegNetX_4GF():
|
||||
model = RegNet(w_a=38.65, w_0=96, w_m=2.43, d=23, group_w=40, bot_mul=1.0, q=8)
|
||||
return model
|
||||
|
||||
def RegNetX_32GF():
|
||||
model = RegNet(w_a=69.86, w_0=320, w_m=2.0, d=23, group_w=168, bot_mul=1.0, q=8)
|
||||
return model
|
||||
|
||||
def RegNetY_200MF():
|
||||
model = RegNet(w_a=36.44, w_0=24, w_m=2.49, d=13, group_w=8, bot_mul=1.0, q=8, se_on=True)
|
||||
return model
|
||||
|
||||
def RegNetY_4GF():
|
||||
model = RegNet(w_a=31.41, w_0=96, w_m=2.24, d=22, group_w=64, bot_mul=1.0, q=8, se_on=True)
|
||||
return model
|
||||
|
||||
def RegNetY_32GF():
|
||||
model = RegNet(w_a=115.89, w_0=232, w_m=2.53, d=20, group_w=232, bot_mul=1.0, q=8, se_on=True)
|
||||
return model
|
Loading…
Reference in New Issue