# 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 paddle import paddle.fluid as fluid import math from paddle.fluid.param_attr import ParamAttr __all__ = ["DenseNet"] class DenseNet(object): def __init__(self, layers=121, bn_size=4, dropout=0, num_classes=None): assert layers in [121, 161, 169, 201, 264], \ "supported layers are {} but input layer is {}".format(supported_layers, layers) self.layers = layers self.bn_size = bn_size self.dropout = dropout self.num_classes = num_classes def __call__(self, input): layers = self.layers densenet_spec = { 121: (64, 32, [6, 12, 24, 16]), 161: (96, 48, [6, 12, 36, 24]), 169: (64, 32, [6, 12, 32, 32]), 201: (64, 32, [6, 12, 48, 32]), 264: (64, 32, [6, 12, 64, 48]) } num_init_features, growth_rate, block_config = densenet_spec[layers] conv = fluid.layers.conv2d( input=input, num_filters=num_init_features, filter_size=7, stride=2, padding=3, act=None, param_attr=ParamAttr(name="conv1_weights"), bias_attr=False) conv = fluid.layers.batch_norm( input=conv, act='relu', param_attr=ParamAttr(name='conv1_bn_scale'), bias_attr=ParamAttr(name='conv1_bn_offset'), moving_mean_name='conv1_bn_mean', moving_variance_name='conv1_bn_variance') conv = fluid.layers.pool2d( input=conv, pool_size=3, pool_stride=2, pool_padding=1, pool_type='max') num_features = num_init_features for i, num_layers in enumerate(block_config): conv = self.make_dense_block( conv, num_layers, self.bn_size, growth_rate, self.dropout, name='conv' + str(i + 2)) num_features = num_features + num_layers * growth_rate if i != len(block_config) - 1: conv = self.make_transition( conv, num_features // 2, name='conv' + str(i + 2) + '_blk') num_features = num_features // 2 conv = fluid.layers.batch_norm( input=conv, act='relu', param_attr=ParamAttr(name='conv5_blk_bn_scale'), bias_attr=ParamAttr(name='conv5_blk_bn_offset'), moving_mean_name='conv5_blk_bn_mean', moving_variance_name='conv5_blk_bn_variance') if self.num_classes: conv = fluid.layers.pool2d( input=conv, pool_type='avg', global_pooling=True) stdv = 1.0 / math.sqrt(conv.shape[1] * 1.0) out = fluid.layers.fc( input=conv, size=self.num_classes, param_attr=fluid.param_attr.ParamAttr( initializer=fluid.initializer.Uniform(-stdv, stdv), name="fc_weights"), bias_attr=ParamAttr(name='fc_offset')) return out def make_transition(self, input, num_output_features, name=None): bn_ac = fluid.layers.batch_norm( input, act='relu', param_attr=ParamAttr(name=name + '_bn_scale'), bias_attr=ParamAttr(name + '_bn_offset'), moving_mean_name=name + '_bn_mean', moving_variance_name=name + '_bn_variance') bn_ac_conv = fluid.layers.conv2d( input=bn_ac, num_filters=num_output_features, filter_size=1, stride=1, act=None, bias_attr=False, param_attr=ParamAttr(name=name + "_weights")) pool = fluid.layers.pool2d( input=bn_ac_conv, pool_size=2, pool_stride=2, pool_type='avg') return pool def make_dense_block(self, input, num_layers, bn_size, growth_rate, dropout, name=None): conv = input for layer in range(num_layers): conv = self.make_dense_layer( conv, growth_rate, bn_size, dropout, name=name + '_' + str(layer + 1)) return conv def make_dense_layer(self, input, growth_rate, bn_size, dropout, name=None): bn_ac = fluid.layers.batch_norm( input, act='relu', param_attr=ParamAttr(name=name + '_x1_bn_scale'), bias_attr=ParamAttr(name + '_x1_bn_offset'), moving_mean_name=name + '_x1_bn_mean', moving_variance_name=name + '_x1_bn_variance') bn_ac_conv = fluid.layers.conv2d( input=bn_ac, num_filters=bn_size * growth_rate, filter_size=1, stride=1, act=None, bias_attr=False, param_attr=ParamAttr(name=name + "_x1_weights")) bn_ac = fluid.layers.batch_norm( bn_ac_conv, act='relu', param_attr=ParamAttr(name=name + '_x2_bn_scale'), bias_attr=ParamAttr(name + '_x2_bn_offset'), moving_mean_name=name + '_x2_bn_mean', moving_variance_name=name + '_x2_bn_variance') bn_ac_conv = fluid.layers.conv2d( input=bn_ac, num_filters=growth_rate, filter_size=3, stride=1, padding=1, act=None, bias_attr=False, param_attr=ParamAttr(name=name + "_x2_weights")) if dropout: bn_ac_conv = fluid.layers.dropout( x=bn_ac_conv, dropout_prob=dropout) bn_ac_conv = fluid.layers.concat([input, bn_ac_conv], axis=1) return bn_ac_conv