Build Trunk Blocks This ended up being somewhat of a cross between https://github.com/tensorflow/tpu/blob/master/models/official/mnasnet/mnasnet_models.py and https://github.com/facebookresearch/maskrcnn-benchmark/blob/master/maskrcnn_benchmark/modeling/backbone/fbnet_builder.py
| 260 | |
| 261 | |
| 262 | class EfficientNetBuilder: |
| 263 | """ Build Trunk Blocks |
| 264 | |
| 265 | This ended up being somewhat of a cross between |
| 266 | https://github.com/tensorflow/tpu/blob/master/models/official/mnasnet/mnasnet_models.py |
| 267 | and |
| 268 | https://github.com/facebookresearch/maskrcnn-benchmark/blob/master/maskrcnn_benchmark/modeling/backbone/fbnet_builder.py |
| 269 | |
| 270 | """ |
| 271 | def __init__(self, output_stride=32, pad_type='', round_chs_fn=round_channels, se_from_exp=False, |
| 272 | act_layer=None, norm_layer=None, se_layer=None, drop_path_rate=0., feature_location=''): |
| 273 | self.output_stride = output_stride |
| 274 | self.pad_type = pad_type |
| 275 | self.round_chs_fn = round_chs_fn |
| 276 | self.se_from_exp = se_from_exp # calculate se channel reduction from expanded (mid) chs |
| 277 | self.act_layer = act_layer |
| 278 | self.norm_layer = norm_layer |
| 279 | self.se_layer = get_attn(se_layer) |
| 280 | try: |
| 281 | self.se_layer(8, rd_ratio=1.0) # test if attn layer accepts rd_ratio arg |
| 282 | self.se_has_ratio = True |
| 283 | except TypeError: |
| 284 | self.se_has_ratio = False |
| 285 | self.drop_path_rate = drop_path_rate |
| 286 | if feature_location == 'depthwise': |
| 287 | # old 'depthwise' mode renamed 'expansion' to match TF impl, old expansion mode didn't make sense |
| 288 | _logger.warning("feature_location=='depthwise' is deprecated, using 'expansion'") |
| 289 | feature_location = 'expansion' |
| 290 | self.feature_location = feature_location |
| 291 | assert feature_location in ('bottleneck', 'expansion', '') |
| 292 | self.verbose = _DEBUG_BUILDER |
| 293 | |
| 294 | # state updated during build, consumed by model |
| 295 | self.in_chs = None |
| 296 | self.features = [] |
| 297 | |
| 298 | def _make_block(self, ba, block_idx, block_count): |
| 299 | drop_path_rate = self.drop_path_rate * block_idx / block_count |
| 300 | bt = ba.pop('block_type') |
| 301 | ba['in_chs'] = self.in_chs |
| 302 | ba['out_chs'] = self.round_chs_fn(ba['out_chs']) |
| 303 | if 'force_in_chs' in ba and ba['force_in_chs']: |
| 304 | # NOTE this is a hack to work around mismatch in TF EdgeEffNet impl |
| 305 | ba['force_in_chs'] = self.round_chs_fn(ba['force_in_chs']) |
| 306 | ba['pad_type'] = self.pad_type |
| 307 | # block act fn overrides the model default |
| 308 | ba['act_layer'] = ba['act_layer'] if ba['act_layer'] is not None else self.act_layer |
| 309 | assert ba['act_layer'] is not None |
| 310 | ba['norm_layer'] = self.norm_layer |
| 311 | ba['drop_path_rate'] = drop_path_rate |
| 312 | if bt != 'cn': |
| 313 | se_ratio = ba.pop('se_ratio') |
| 314 | if se_ratio and self.se_layer is not None: |
| 315 | if not self.se_from_exp: |
| 316 | # adjust se_ratio by expansion ratio if calculating se channels from block input |
| 317 | se_ratio /= ba.get('exp_ratio', 1.0) |
| 318 | if self.se_has_ratio: |
| 319 | ba['se_layer'] = partial(self.se_layer, rd_ratio=se_ratio) |