253 lines
8.5 KiB
Python
253 lines
8.5 KiB
Python
# 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 warnings
|
|
|
|
import paddle.fluid as fluid
|
|
|
|
|
|
def initial_type(name,
|
|
input,
|
|
op_type,
|
|
fan_out,
|
|
init="google",
|
|
use_bias=False,
|
|
filter_size=0,
|
|
stddev=0.02):
|
|
if init == "kaiming":
|
|
if op_type == 'conv':
|
|
fan_in = input.shape[1] * filter_size * filter_size
|
|
elif op_type == 'deconv':
|
|
fan_in = fan_out * filter_size * filter_size
|
|
else:
|
|
if len(input.shape) > 2:
|
|
fan_in = input.shape[1] * input.shape[2] * input.shape[3]
|
|
else:
|
|
fan_in = input.shape[1]
|
|
bound = 1 / math.sqrt(fan_in)
|
|
param_attr = fluid.ParamAttr(
|
|
name=name + "_weights",
|
|
initializer=fluid.initializer.Uniform(
|
|
low=-bound, high=bound))
|
|
if use_bias == True:
|
|
bias_attr = fluid.ParamAttr(
|
|
name=name + '_offset',
|
|
initializer=fluid.initializer.Uniform(
|
|
low=-bound, high=bound))
|
|
else:
|
|
bias_attr = False
|
|
elif init == 'google':
|
|
n = filter_size * filter_size * fan_out
|
|
param_attr = fluid.ParamAttr(
|
|
name=name + "_weights",
|
|
initializer=fluid.initializer.NormalInitializer(
|
|
loc=0.0, scale=math.sqrt(2.0 / n)))
|
|
if use_bias == True:
|
|
bias_attr = fluid.ParamAttr(
|
|
name=name + "_offset",
|
|
initializer=fluid.initializer.Constant(0.0))
|
|
else:
|
|
bias_attr = False
|
|
|
|
else:
|
|
param_attr = fluid.ParamAttr(
|
|
name=name + "_weights",
|
|
initializer=fluid.initializer.NormalInitializer(
|
|
loc=0.0, scale=stddev))
|
|
if use_bias == True:
|
|
bias_attr = fluid.ParamAttr(
|
|
name=name + "_offset",
|
|
initializer=fluid.initializer.Constant(0.0))
|
|
else:
|
|
bias_attr = False
|
|
return param_attr, bias_attr
|
|
|
|
|
|
def cal_padding(img_size, stride, filter_size, dilation=1):
|
|
"""Calculate padding size."""
|
|
if img_size % stride == 0:
|
|
out_size = max(filter_size - stride, 0)
|
|
else:
|
|
out_size = max(filter_size - (img_size % stride), 0)
|
|
return out_size // 2, out_size - out_size // 2
|
|
|
|
|
|
def init_batch_norm_layer(name="batch_norm"):
|
|
param_attr = fluid.ParamAttr(
|
|
name=name + '_scale', initializer=fluid.initializer.Constant(1.0))
|
|
bias_attr = fluid.ParamAttr(
|
|
name=name + '_offset',
|
|
initializer=fluid.initializer.Constant(value=0.0))
|
|
return param_attr, bias_attr
|
|
|
|
|
|
def init_fc_layer(fout, name='fc'):
|
|
n = fout # fan-out
|
|
init_range = 1.0 / math.sqrt(n)
|
|
|
|
param_attr = fluid.ParamAttr(
|
|
name=name + '_weights',
|
|
initializer=fluid.initializer.UniformInitializer(
|
|
low=-init_range, high=init_range))
|
|
bias_attr = fluid.ParamAttr(
|
|
name=name + '_offset',
|
|
initializer=fluid.initializer.Constant(value=0.0))
|
|
return param_attr, bias_attr
|
|
|
|
|
|
def norm_layer(input, norm_type='batch_norm', name=None):
|
|
if norm_type == 'batch_norm':
|
|
param_attr = fluid.ParamAttr(
|
|
name=name + '_weights',
|
|
initializer=fluid.initializer.Constant(1.0))
|
|
bias_attr = fluid.ParamAttr(
|
|
name=name + '_offset',
|
|
initializer=fluid.initializer.Constant(value=0.0))
|
|
return fluid.layers.batch_norm(
|
|
input,
|
|
param_attr=param_attr,
|
|
bias_attr=bias_attr,
|
|
moving_mean_name=name + '_mean',
|
|
moving_variance_name=name + '_variance')
|
|
|
|
elif norm_type == 'instance_norm':
|
|
helper = fluid.layer_helper.LayerHelper("instance_norm", **locals())
|
|
dtype = helper.input_dtype()
|
|
epsilon = 1e-5
|
|
mean = fluid.layers.reduce_mean(input, dim=[2, 3], keep_dim=True)
|
|
var = fluid.layers.reduce_mean(
|
|
fluid.layers.square(input - mean), dim=[2, 3], keep_dim=True)
|
|
if name is not None:
|
|
scale_name = name + "_scale"
|
|
offset_name = name + "_offset"
|
|
scale_param = fluid.ParamAttr(
|
|
name=scale_name,
|
|
initializer=fluid.initializer.Constant(1.0),
|
|
trainable=True)
|
|
offset_param = fluid.ParamAttr(
|
|
name=offset_name,
|
|
initializer=fluid.initializer.Constant(0.0),
|
|
trainable=True)
|
|
scale = helper.create_parameter(
|
|
attr=scale_param, shape=input.shape[1:2], dtype=dtype)
|
|
offset = helper.create_parameter(
|
|
attr=offset_param, shape=input.shape[1:2], dtype=dtype)
|
|
|
|
tmp = fluid.layers.elementwise_mul(x=(input - mean), y=scale, axis=1)
|
|
tmp = tmp / fluid.layers.sqrt(var + epsilon)
|
|
tmp = fluid.layers.elementwise_add(tmp, offset, axis=1)
|
|
return tmp
|
|
else:
|
|
raise NotImplementedError("norm tyoe: [%s] is not support" % norm_type)
|
|
|
|
|
|
def conv2d(input,
|
|
num_filters=64,
|
|
filter_size=7,
|
|
stride=1,
|
|
stddev=0.02,
|
|
padding=0,
|
|
groups=None,
|
|
name="conv2d",
|
|
norm=None,
|
|
act=None,
|
|
relufactor=0.0,
|
|
use_bias=False,
|
|
padding_type=None,
|
|
initial="normal",
|
|
use_cudnn=True):
|
|
|
|
if padding != 0 and padding_type != None:
|
|
warnings.warn(
|
|
'padding value and padding type are set in the same time, and the final padding width and padding height are computed by padding_type'
|
|
)
|
|
|
|
param_attr, bias_attr = initial_type(
|
|
name=name,
|
|
input=input,
|
|
op_type='conv',
|
|
fan_out=num_filters,
|
|
init=initial,
|
|
use_bias=use_bias,
|
|
filter_size=filter_size,
|
|
stddev=stddev)
|
|
|
|
def get_padding(filter_size, stride=1, dilation=1):
|
|
padding = ((stride - 1) + dilation * (filter_size - 1)) // 2
|
|
return padding
|
|
|
|
need_crop = False
|
|
if padding_type == "SAME":
|
|
top_padding, bottom_padding = cal_padding(input.shape[2], stride,
|
|
filter_size)
|
|
left_padding, right_padding = cal_padding(input.shape[2], stride,
|
|
filter_size)
|
|
height_padding = bottom_padding
|
|
width_padding = right_padding
|
|
if top_padding != bottom_padding or left_padding != right_padding:
|
|
height_padding = top_padding + stride
|
|
width_padding = left_padding + stride
|
|
need_crop = True
|
|
padding = [height_padding, width_padding]
|
|
elif padding_type == "VALID":
|
|
height_padding = 0
|
|
width_padding = 0
|
|
padding = [height_padding, width_padding]
|
|
elif padding_type == "DYNAMIC":
|
|
padding = get_padding(filter_size, stride)
|
|
else:
|
|
padding = padding
|
|
|
|
conv = fluid.layers.conv2d(
|
|
input,
|
|
num_filters,
|
|
filter_size,
|
|
groups=groups,
|
|
name=name,
|
|
stride=stride,
|
|
padding=padding,
|
|
use_cudnn=use_cudnn,
|
|
param_attr=param_attr,
|
|
bias_attr=bias_attr)
|
|
|
|
if need_crop:
|
|
conv = conv[:, :, 1:, 1:]
|
|
|
|
if norm is not None:
|
|
conv = norm_layer(input=conv, norm_type=norm, name=name + "_norm")
|
|
if act == 'relu':
|
|
conv = fluid.layers.relu(conv, name=name + '_relu')
|
|
elif act == 'leaky_relu':
|
|
conv = fluid.layers.leaky_relu(
|
|
conv, alpha=relufactor, name=name + '_leaky_relu')
|
|
elif act == 'tanh':
|
|
conv = fluid.layers.tanh(conv, name=name + '_tanh')
|
|
elif act == 'sigmoid':
|
|
conv = fluid.layers.sigmoid(conv, name=name + '_sigmoid')
|
|
elif act == 'swish':
|
|
conv = fluid.layers.swish(conv, name=name + '_swish')
|
|
elif act == 'relu6':
|
|
conv = fluid.layers.relu6(conv, name=name + '_relu6')
|
|
elif act == None:
|
|
conv = conv
|
|
else:
|
|
raise NotImplementedError("activation: [%s] is not support" % act)
|
|
|
|
return conv
|