24
24
from __future__ import division
25
25
from __future__ import print_function
26
26
27
+ import functools
28
+
27
29
import tensorflow .compat .v2 as tf
28
30
29
31
from tensorflow .python .keras import backend
@@ -39,6 +41,7 @@ def __init__(self,
39
41
max_level = 7 ,
40
42
fpn_feat_dims = 256 ,
41
43
use_separable_conv = False ,
44
+ use_batch_norm = True ,
42
45
batch_norm_relu = nn_ops .BatchNormRelu ):
43
46
"""FPN initialization function.
44
47
@@ -48,60 +51,46 @@ def __init__(self,
48
51
fpn_feat_dims: `int` number of filters in FPN layers.
49
52
use_separable_conv: `bool`, if True use separable convolution for
50
53
convolution in FPN layers.
54
+ use_batch_norm: 'bool', indicating whether batchnorm layers are added.
51
55
batch_norm_relu: an operation that includes a batch normalization layer
52
56
followed by a relu layer(optional).
53
57
"""
54
58
self ._min_level = min_level
55
59
self ._max_level = max_level
56
60
self ._fpn_feat_dims = fpn_feat_dims
61
+ if use_separable_conv :
62
+ self ._conv2d_op = functools .partial (
63
+ tf .keras .layers .SeparableConv2D , depth_multiplier = 1 )
64
+ else :
65
+ self ._conv2d_op = tf .keras .layers .Conv2D
66
+ self ._use_batch_norm = use_batch_norm
57
67
self ._batch_norm_relu = batch_norm_relu
58
68
59
69
self ._batch_norm_relus = {}
60
70
self ._lateral_conv2d_op = {}
61
71
self ._post_hoc_conv2d_op = {}
62
72
self ._coarse_conv2d_op = {}
63
73
for level in range (self ._min_level , self ._max_level + 1 ):
64
- self ._batch_norm_relus [level ] = batch_norm_relu (
65
- relu = False , name = 'p%d-bn' % level )
66
- if use_separable_conv :
67
- self ._lateral_conv2d_op [level ] = tf .keras .layers .SeparableConv2D (
68
- filters = self ._fpn_feat_dims ,
69
- kernel_size = (1 , 1 ),
70
- padding = 'same' ,
71
- depth_multiplier = 1 ,
72
- name = 'l%d' % level )
73
- self ._post_hoc_conv2d_op [level ] = tf .keras .layers .SeparableConv2D (
74
- filters = self ._fpn_feat_dims ,
75
- strides = (1 , 1 ),
76
- kernel_size = (3 , 3 ),
77
- padding = 'same' ,
78
- depth_multiplier = 1 ,
79
- name = 'post_hoc_d%d' % level )
80
- self ._coarse_conv2d_op [level ] = tf .keras .layers .SeparableConv2D (
81
- filters = self ._fpn_feat_dims ,
82
- strides = (2 , 2 ),
83
- kernel_size = (3 , 3 ),
84
- padding = 'same' ,
85
- depth_multiplier = 1 ,
86
- name = 'p%d' % level )
87
- else :
88
- self ._lateral_conv2d_op [level ] = tf .keras .layers .Conv2D (
89
- filters = self ._fpn_feat_dims ,
90
- kernel_size = (1 , 1 ),
91
- padding = 'same' ,
92
- name = 'l%d' % level )
93
- self ._post_hoc_conv2d_op [level ] = tf .keras .layers .Conv2D (
94
- filters = self ._fpn_feat_dims ,
95
- strides = (1 , 1 ),
96
- kernel_size = (3 , 3 ),
97
- padding = 'same' ,
98
- name = 'post_hoc_d%d' % level )
99
- self ._coarse_conv2d_op [level ] = tf .keras .layers .Conv2D (
100
- filters = self ._fpn_feat_dims ,
101
- strides = (2 , 2 ),
102
- kernel_size = (3 , 3 ),
103
- padding = 'same' ,
104
- name = 'p%d' % level )
74
+ if self ._use_batch_norm :
75
+ self ._batch_norm_relus [level ] = batch_norm_relu (
76
+ relu = False , name = 'p%d-bn' % level )
77
+ self ._lateral_conv2d_op [level ] = self ._conv2d_op (
78
+ filters = self ._fpn_feat_dims ,
79
+ kernel_size = (1 , 1 ),
80
+ padding = 'same' ,
81
+ name = 'l%d' % level )
82
+ self ._post_hoc_conv2d_op [level ] = self ._conv2d_op (
83
+ filters = self ._fpn_feat_dims ,
84
+ strides = (1 , 1 ),
85
+ kernel_size = (3 , 3 ),
86
+ padding = 'same' ,
87
+ name = 'post_hoc_d%d' % level )
88
+ self ._coarse_conv2d_op [level ] = self ._conv2d_op (
89
+ filters = self ._fpn_feat_dims ,
90
+ strides = (2 , 2 ),
91
+ kernel_size = (3 , 3 ),
92
+ padding = 'same' ,
93
+ name = 'p%d' % level )
105
94
106
95
def __call__ (self , multilevel_features , is_training = None ):
107
96
"""Returns the FPN features for a given multilevel features.
@@ -117,7 +106,7 @@ def __call__(self, multilevel_features, is_training=None):
117
106
[min_level, min_level + 1, ..., max_level]. The values are corresponding
118
107
FPN features with shape [batch_size, height_l, width_l, fpn_feat_dims].
119
108
"""
120
- input_levels = multilevel_features .keys ()
109
+ input_levels = list ( multilevel_features .keys () )
121
110
if min (input_levels ) > self ._min_level :
122
111
raise ValueError (
123
112
'The minimum backbone level %d should be ' % (min (input_levels )) +
@@ -146,8 +135,9 @@ def __call__(self, multilevel_features, is_training=None):
146
135
if level > backbone_max_level + 1 :
147
136
feats_in = tf .nn .relu (feats_in )
148
137
feats [level ] = self ._coarse_conv2d_op [level ](feats_in )
149
- # Adds batch_norm layer.
150
- for level in range (self ._min_level , self ._max_level + 1 ):
151
- feats [level ] = self ._batch_norm_relus [level ](
152
- feats [level ], is_training = is_training )
138
+ if self ._use_batch_norm :
139
+ # Adds batch_norm layer.
140
+ for level in range (self ._min_level , self ._max_level + 1 ):
141
+ feats [level ] = self ._batch_norm_relus [level ](
142
+ feats [level ], is_training = is_training )
153
143
return feats
0 commit comments