efficientnet.py 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901
  1. import paddle
  2. from paddle import ParamAttr
  3. import paddle.nn as nn
  4. import paddle.nn.functional as F
  5. from paddle.nn import Conv2D, BatchNorm, Linear, Dropout
  6. from paddle.nn import AdaptiveAvgPool2D, MaxPool2D, AvgPool2D
  7. import math
  8. import collections
  9. import re
  10. import copy
  11. __all__ = [
  12. 'EfficientNet', 'EfficientNetB0_small', 'EfficientNetB0', 'EfficientNetB1',
  13. 'EfficientNetB2', 'EfficientNetB3', 'EfficientNetB4', 'EfficientNetB5',
  14. 'EfficientNetB6', 'EfficientNetB7'
  15. ]
  16. GlobalParams = collections.namedtuple('GlobalParams', [
  17. 'batch_norm_momentum',
  18. 'batch_norm_epsilon',
  19. 'dropout_rate',
  20. 'num_classes',
  21. 'width_coefficient',
  22. 'depth_coefficient',
  23. 'depth_divisor',
  24. 'min_depth',
  25. 'drop_connect_rate',
  26. ])
  27. BlockArgs = collections.namedtuple('BlockArgs', [
  28. 'kernel_size', 'num_repeat', 'input_filters', 'output_filters',
  29. 'expand_ratio', 'id_skip', 'stride', 'se_ratio'
  30. ])
  31. GlobalParams.__new__.__defaults__ = (None, ) * len(GlobalParams._fields)
  32. BlockArgs.__new__.__defaults__ = (None, ) * len(BlockArgs._fields)
  33. def efficientnet_params(model_name):
  34. """ Map EfficientNet model name to parameter coefficients. """
  35. params_dict = {
  36. # Coefficients: width,depth,resolution,dropout
  37. 'efficientnet-b0': (1.0, 1.0, 224, 0.2),
  38. 'efficientnet-b1': (1.0, 1.1, 240, 0.2),
  39. 'efficientnet-b2': (1.1, 1.2, 260, 0.3),
  40. 'efficientnet-b3': (1.2, 1.4, 300, 0.3),
  41. 'efficientnet-b4': (1.4, 1.8, 380, 0.4),
  42. 'efficientnet-b5': (1.6, 2.2, 456, 0.4),
  43. 'efficientnet-b6': (1.8, 2.6, 528, 0.5),
  44. 'efficientnet-b7': (2.0, 3.1, 600, 0.5),
  45. }
  46. return params_dict[model_name]
  47. def efficientnet(width_coefficient=None,
  48. depth_coefficient=None,
  49. dropout_rate=0.2,
  50. drop_connect_rate=0.2):
  51. """ Get block arguments according to parameter and coefficients. """
  52. blocks_args = [
  53. 'r1_k3_s11_e1_i32_o16_se0.25',
  54. 'r2_k3_s22_e6_i16_o24_se0.25',
  55. 'r2_k5_s22_e6_i24_o40_se0.25',
  56. 'r3_k3_s22_e6_i40_o80_se0.25',
  57. 'r3_k5_s11_e6_i80_o112_se0.25',
  58. 'r4_k5_s22_e6_i112_o192_se0.25',
  59. 'r1_k3_s11_e6_i192_o320_se0.25',
  60. ]
  61. blocks_args = BlockDecoder.decode(blocks_args)
  62. global_params = GlobalParams(
  63. batch_norm_momentum=0.99,
  64. batch_norm_epsilon=1e-3,
  65. dropout_rate=dropout_rate,
  66. drop_connect_rate=drop_connect_rate,
  67. num_classes=1000,
  68. width_coefficient=width_coefficient,
  69. depth_coefficient=depth_coefficient,
  70. depth_divisor=8,
  71. min_depth=None)
  72. return blocks_args, global_params
  73. def get_model_params(model_name, override_params):
  74. """ Get the block args and global params for a given model """
  75. if model_name.startswith('efficientnet'):
  76. w, d, _, p = efficientnet_params(model_name)
  77. blocks_args, global_params = efficientnet(
  78. width_coefficient=w, depth_coefficient=d, dropout_rate=p)
  79. else:
  80. raise NotImplementedError('model name is not pre-defined: %s' %
  81. model_name)
  82. if override_params:
  83. global_params = global_params._replace(**override_params)
  84. return blocks_args, global_params
  85. def round_filters(filters, global_params):
  86. """ Calculate and round number of filters based on depth multiplier. """
  87. multiplier = global_params.width_coefficient
  88. if not multiplier:
  89. return filters
  90. divisor = global_params.depth_divisor
  91. min_depth = global_params.min_depth
  92. filters *= multiplier
  93. min_depth = min_depth or divisor
  94. new_filters = max(min_depth,
  95. int(filters + divisor / 2) // divisor * divisor)
  96. if new_filters < 0.9 * filters: # prevent rounding by more than 10%
  97. new_filters += divisor
  98. return int(new_filters)
  99. def round_repeats(repeats, global_params):
  100. """ Round number of filters based on depth multiplier. """
  101. multiplier = global_params.depth_coefficient
  102. if not multiplier:
  103. return repeats
  104. return int(math.ceil(multiplier * repeats))
  105. class BlockDecoder(object):
  106. """
  107. Block Decoder, straight from the official TensorFlow repository.
  108. """
  109. @staticmethod
  110. def _decode_block_string(block_string):
  111. """ Gets a block through a string notation of arguments. """
  112. assert isinstance(block_string, str)
  113. ops = block_string.split('_')
  114. options = {}
  115. for op in ops:
  116. splits = re.split(r'(\d.*)', op)
  117. if len(splits) >= 2:
  118. key, value = splits[:2]
  119. options[key] = value
  120. # Check stride
  121. cond_1 = ('s' in options and len(options['s']) == 1)
  122. cond_2 = ((len(options['s']) == 2) and
  123. (options['s'][0] == options['s'][1]))
  124. assert (cond_1 or cond_2)
  125. return BlockArgs(
  126. kernel_size=int(options['k']),
  127. num_repeat=int(options['r']),
  128. input_filters=int(options['i']),
  129. output_filters=int(options['o']),
  130. expand_ratio=int(options['e']),
  131. id_skip=('noskip' not in block_string),
  132. se_ratio=float(options['se']) if 'se' in options else None,
  133. stride=[int(options['s'][0])])
  134. @staticmethod
  135. def _encode_block_string(block):
  136. """Encodes a block to a string."""
  137. args = [
  138. 'r%d' % block.num_repeat, 'k%d' % block.kernel_size, 's%d%d' %
  139. (block.strides[0], block.strides[1]), 'e%s' % block.expand_ratio,
  140. 'i%d' % block.input_filters, 'o%d' % block.output_filters
  141. ]
  142. if 0 < block.se_ratio <= 1:
  143. args.append('se%s' % block.se_ratio)
  144. if block.id_skip is False:
  145. args.append('noskip')
  146. return '_'.join(args)
  147. @staticmethod
  148. def decode(string_list):
  149. """
  150. Decode a list of string notations to specify blocks in the network.
  151. string_list: list of strings, each string is a notation of block
  152. return
  153. list of BlockArgs namedtuples of block args
  154. """
  155. assert isinstance(string_list, list)
  156. blocks_args = []
  157. for block_string in string_list:
  158. blocks_args.append(BlockDecoder._decode_block_string(block_string))
  159. return blocks_args
  160. @staticmethod
  161. def encode(blocks_args):
  162. """
  163. Encodes a list of BlockArgs to a list of strings.
  164. :param blocks_args: a list of BlockArgs namedtuples of block args
  165. :return: a list of strings, each string is a notation of block
  166. """
  167. block_strings = []
  168. for block in blocks_args:
  169. block_strings.append(BlockDecoder._encode_block_string(block))
  170. return block_strings
  171. def initial_type(name, use_bias=False):
  172. param_attr = ParamAttr(name=name + "_weights")
  173. if use_bias:
  174. bias_attr = ParamAttr(name=name + "_offset")
  175. else:
  176. bias_attr = False
  177. return param_attr, bias_attr
  178. def init_batch_norm_layer(name="batch_norm"):
  179. param_attr = ParamAttr(name=name + "_scale")
  180. bias_attr = ParamAttr(name=name + "_offset")
  181. return param_attr, bias_attr
  182. def init_fc_layer(name="fc"):
  183. param_attr = ParamAttr(name=name + "_weights")
  184. bias_attr = ParamAttr(name=name + "_offset")
  185. return param_attr, bias_attr
  186. def cal_padding(img_size, stride, filter_size, dilation=1):
  187. """Calculate padding size."""
  188. if img_size % stride == 0:
  189. out_size = max(filter_size - stride, 0)
  190. else:
  191. out_size = max(filter_size - (img_size % stride), 0)
  192. return out_size // 2, out_size - out_size // 2
  193. inp_shape = {
  194. "b0_small": [224, 112, 112, 56, 28, 14, 14, 7],
  195. "b0": [224, 112, 112, 56, 28, 14, 14, 7],
  196. "b1": [240, 120, 120, 60, 30, 15, 15, 8],
  197. "b2": [260, 130, 130, 65, 33, 17, 17, 9],
  198. "b3": [300, 150, 150, 75, 38, 19, 19, 10],
  199. "b4": [380, 190, 190, 95, 48, 24, 24, 12],
  200. "b5": [456, 228, 228, 114, 57, 29, 29, 15],
  201. "b6": [528, 264, 264, 132, 66, 33, 33, 17],
  202. "b7": [600, 300, 300, 150, 75, 38, 38, 19]
  203. }
  204. def _drop_connect(inputs, prob, is_test):
  205. if is_test:
  206. output = inputs
  207. else:
  208. keep_prob = 1.0 - prob
  209. inputs_shape = paddle.shape(inputs)
  210. random_tensor = keep_prob + paddle.rand(
  211. shape=[inputs_shape[0], 1, 1, 1])
  212. binary_tensor = paddle.floor(random_tensor)
  213. output = paddle.multiply(inputs, binary_tensor) / keep_prob
  214. return output
  215. class Conv2ds(nn.Layer):
  216. def __init__(self,
  217. input_channels,
  218. output_channels,
  219. filter_size,
  220. stride=1,
  221. padding=0,
  222. groups=None,
  223. name="conv2d",
  224. act=None,
  225. use_bias=False,
  226. padding_type=None,
  227. model_name=None,
  228. cur_stage=None):
  229. super(Conv2ds, self).__init__()
  230. assert act in [None, "swish", "sigmoid"]
  231. self.act = act
  232. param_attr, bias_attr = initial_type(name=name, use_bias=use_bias)
  233. def get_padding(filter_size, stride=1, dilation=1):
  234. padding = ((stride - 1) + dilation * (filter_size - 1)) // 2
  235. return padding
  236. inps = 1 if model_name == None and cur_stage == None else inp_shape[
  237. model_name][cur_stage]
  238. self.need_crop = False
  239. if padding_type == "SAME":
  240. top_padding, bottom_padding = cal_padding(inps, stride,
  241. filter_size)
  242. left_padding, right_padding = cal_padding(inps, stride,
  243. filter_size)
  244. height_padding = bottom_padding
  245. width_padding = right_padding
  246. if top_padding != bottom_padding or left_padding != right_padding:
  247. height_padding = top_padding + stride
  248. width_padding = left_padding + stride
  249. self.need_crop = True
  250. padding = [height_padding, width_padding]
  251. elif padding_type == "VALID":
  252. height_padding = 0
  253. width_padding = 0
  254. padding = [height_padding, width_padding]
  255. elif padding_type == "DYNAMIC":
  256. padding = get_padding(filter_size, stride)
  257. else:
  258. padding = padding_type
  259. groups = 1 if groups is None else groups
  260. self._conv = Conv2D(
  261. input_channels,
  262. output_channels,
  263. filter_size,
  264. groups=groups,
  265. stride=stride,
  266. # act=act,
  267. padding=padding,
  268. weight_attr=param_attr,
  269. bias_attr=bias_attr)
  270. def forward(self, inputs):
  271. x = self._conv(inputs)
  272. if self.act == "swish":
  273. x = F.swish(x)
  274. elif self.act == "sigmoid":
  275. x = F.sigmoid(x)
  276. if self.need_crop:
  277. x = x[:, :, 1:, 1:]
  278. return x
  279. class ConvBNLayer(nn.Layer):
  280. def __init__(self,
  281. input_channels,
  282. filter_size,
  283. output_channels,
  284. stride=1,
  285. num_groups=1,
  286. padding_type="SAME",
  287. conv_act=None,
  288. bn_act="swish",
  289. use_bn=True,
  290. use_bias=False,
  291. name=None,
  292. conv_name=None,
  293. bn_name=None,
  294. model_name=None,
  295. cur_stage=None):
  296. super(ConvBNLayer, self).__init__()
  297. self._conv = Conv2ds(
  298. input_channels=input_channels,
  299. output_channels=output_channels,
  300. filter_size=filter_size,
  301. stride=stride,
  302. groups=num_groups,
  303. act=conv_act,
  304. padding_type=padding_type,
  305. name=conv_name,
  306. use_bias=use_bias,
  307. model_name=model_name,
  308. cur_stage=cur_stage)
  309. self.use_bn = use_bn
  310. if use_bn is True:
  311. bn_name = name + bn_name
  312. param_attr, bias_attr = init_batch_norm_layer(bn_name)
  313. self._bn = BatchNorm(
  314. num_channels=output_channels,
  315. act=bn_act,
  316. momentum=0.99,
  317. epsilon=0.001,
  318. moving_mean_name=bn_name + "_mean",
  319. moving_variance_name=bn_name + "_variance",
  320. param_attr=param_attr,
  321. bias_attr=bias_attr)
  322. def forward(self, inputs):
  323. if self.use_bn:
  324. x = self._conv(inputs)
  325. x = self._bn(x)
  326. return x
  327. else:
  328. return self._conv(inputs)
  329. class ExpandConvNorm(nn.Layer):
  330. def __init__(self,
  331. input_channels,
  332. block_args,
  333. padding_type,
  334. name=None,
  335. model_name=None,
  336. cur_stage=None):
  337. super(ExpandConvNorm, self).__init__()
  338. self.oup = block_args.input_filters * block_args.expand_ratio
  339. self.expand_ratio = block_args.expand_ratio
  340. if self.expand_ratio != 1:
  341. self._conv = ConvBNLayer(
  342. input_channels,
  343. 1,
  344. self.oup,
  345. bn_act=None,
  346. padding_type=padding_type,
  347. name=name,
  348. conv_name=name + "_expand_conv",
  349. bn_name="_bn0",
  350. model_name=model_name,
  351. cur_stage=cur_stage)
  352. def forward(self, inputs):
  353. if self.expand_ratio != 1:
  354. return self._conv(inputs)
  355. else:
  356. return inputs
  357. class DepthwiseConvNorm(nn.Layer):
  358. def __init__(self,
  359. input_channels,
  360. block_args,
  361. padding_type,
  362. name=None,
  363. model_name=None,
  364. cur_stage=None):
  365. super(DepthwiseConvNorm, self).__init__()
  366. self.k = block_args.kernel_size
  367. self.s = block_args.stride
  368. if isinstance(self.s, list) or isinstance(self.s, tuple):
  369. self.s = self.s[0]
  370. oup = block_args.input_filters * block_args.expand_ratio
  371. self._conv = ConvBNLayer(
  372. input_channels,
  373. self.k,
  374. oup,
  375. self.s,
  376. num_groups=input_channels,
  377. bn_act=None,
  378. padding_type=padding_type,
  379. name=name,
  380. conv_name=name + "_depthwise_conv",
  381. bn_name="_bn1",
  382. model_name=model_name,
  383. cur_stage=cur_stage)
  384. def forward(self, inputs):
  385. return self._conv(inputs)
  386. class ProjectConvNorm(nn.Layer):
  387. def __init__(self,
  388. input_channels,
  389. block_args,
  390. padding_type,
  391. name=None,
  392. model_name=None,
  393. cur_stage=None):
  394. super(ProjectConvNorm, self).__init__()
  395. final_oup = block_args.output_filters
  396. self._conv = ConvBNLayer(
  397. input_channels,
  398. 1,
  399. final_oup,
  400. bn_act=None,
  401. padding_type=padding_type,
  402. name=name,
  403. conv_name=name + "_project_conv",
  404. bn_name="_bn2",
  405. model_name=model_name,
  406. cur_stage=cur_stage)
  407. def forward(self, inputs):
  408. return self._conv(inputs)
  409. class SEBlock(nn.Layer):
  410. def __init__(self,
  411. input_channels,
  412. num_squeezed_channels,
  413. oup,
  414. padding_type,
  415. name=None,
  416. model_name=None,
  417. cur_stage=None):
  418. super(SEBlock, self).__init__()
  419. self._pool = AdaptiveAvgPool2D(1)
  420. self._conv1 = Conv2ds(
  421. input_channels,
  422. num_squeezed_channels,
  423. 1,
  424. use_bias=True,
  425. padding_type=padding_type,
  426. act="swish",
  427. name=name + "_se_reduce")
  428. self._conv2 = Conv2ds(
  429. num_squeezed_channels,
  430. oup,
  431. 1,
  432. act="sigmoid",
  433. use_bias=True,
  434. padding_type=padding_type,
  435. name=name + "_se_expand")
  436. def forward(self, inputs):
  437. x = self._pool(inputs)
  438. x = self._conv1(x)
  439. x = self._conv2(x)
  440. out = paddle.multiply(inputs, x)
  441. return out
  442. class MbConvBlock(nn.Layer):
  443. def __init__(self,
  444. input_channels,
  445. block_args,
  446. padding_type,
  447. use_se,
  448. name=None,
  449. drop_connect_rate=None,
  450. model_name=None,
  451. cur_stage=None):
  452. super(MbConvBlock, self).__init__()
  453. oup = block_args.input_filters * block_args.expand_ratio
  454. self.block_args = block_args
  455. self.has_se = use_se and (block_args.se_ratio is not None) and (
  456. 0 < block_args.se_ratio <= 1)
  457. self.id_skip = block_args.id_skip
  458. self.expand_ratio = block_args.expand_ratio
  459. self.drop_connect_rate = drop_connect_rate
  460. if self.expand_ratio != 1:
  461. self._ecn = ExpandConvNorm(
  462. input_channels,
  463. block_args,
  464. padding_type=padding_type,
  465. name=name,
  466. model_name=model_name,
  467. cur_stage=cur_stage)
  468. self._dcn = DepthwiseConvNorm(
  469. input_channels * block_args.expand_ratio,
  470. block_args,
  471. padding_type=padding_type,
  472. name=name,
  473. model_name=model_name,
  474. cur_stage=cur_stage)
  475. if self.has_se:
  476. num_squeezed_channels = max(
  477. 1, int(block_args.input_filters * block_args.se_ratio))
  478. self._se = SEBlock(
  479. input_channels * block_args.expand_ratio,
  480. num_squeezed_channels,
  481. oup,
  482. padding_type=padding_type,
  483. name=name,
  484. model_name=model_name,
  485. cur_stage=cur_stage)
  486. self._pcn = ProjectConvNorm(
  487. input_channels * block_args.expand_ratio,
  488. block_args,
  489. padding_type=padding_type,
  490. name=name,
  491. model_name=model_name,
  492. cur_stage=cur_stage)
  493. def forward(self, inputs):
  494. x = inputs
  495. if self.expand_ratio != 1:
  496. x = self._ecn(x)
  497. x = F.swish(x)
  498. x = self._dcn(x)
  499. x = F.swish(x)
  500. if self.has_se:
  501. x = self._se(x)
  502. x = self._pcn(x)
  503. if self.id_skip and \
  504. self.block_args.stride == 1 and \
  505. self.block_args.input_filters == self.block_args.output_filters:
  506. if self.drop_connect_rate:
  507. x = _drop_connect(x, self.drop_connect_rate, not self.training)
  508. x = paddle.add(x, inputs)
  509. return x
  510. class ConvStemNorm(nn.Layer):
  511. def __init__(self,
  512. input_channels,
  513. padding_type,
  514. _global_params,
  515. name=None,
  516. model_name=None,
  517. cur_stage=None):
  518. super(ConvStemNorm, self).__init__()
  519. output_channels = round_filters(32, _global_params)
  520. self._conv = ConvBNLayer(
  521. input_channels,
  522. filter_size=3,
  523. output_channels=output_channels,
  524. stride=2,
  525. bn_act=None,
  526. padding_type=padding_type,
  527. name="",
  528. conv_name="_conv_stem",
  529. bn_name="_bn0",
  530. model_name=model_name,
  531. cur_stage=cur_stage)
  532. def forward(self, inputs):
  533. return self._conv(inputs)
  534. class ExtractFeatures(nn.Layer):
  535. def __init__(self,
  536. input_channels,
  537. _block_args,
  538. _global_params,
  539. padding_type,
  540. use_se,
  541. model_name=None):
  542. super(ExtractFeatures, self).__init__()
  543. self._global_params = _global_params
  544. self._conv_stem = ConvStemNorm(
  545. input_channels,
  546. padding_type=padding_type,
  547. _global_params=_global_params,
  548. model_name=model_name,
  549. cur_stage=0)
  550. self.block_args_copy = copy.deepcopy(_block_args)
  551. idx = 0
  552. block_size = 0
  553. for block_arg in self.block_args_copy:
  554. block_arg = block_arg._replace(
  555. input_filters=round_filters(block_arg.input_filters,
  556. _global_params),
  557. output_filters=round_filters(block_arg.output_filters,
  558. _global_params),
  559. num_repeat=round_repeats(block_arg.num_repeat, _global_params))
  560. block_size += 1
  561. for _ in range(block_arg.num_repeat - 1):
  562. block_size += 1
  563. self.conv_seq = []
  564. cur_stage = 1
  565. for block_args in _block_args:
  566. block_args = block_args._replace(
  567. input_filters=round_filters(block_args.input_filters,
  568. _global_params),
  569. output_filters=round_filters(block_args.output_filters,
  570. _global_params),
  571. num_repeat=round_repeats(block_args.num_repeat,
  572. _global_params))
  573. drop_connect_rate = self._global_params.drop_connect_rate
  574. if drop_connect_rate:
  575. drop_connect_rate *= float(idx) / block_size
  576. _mc_block = self.add_sublayer(
  577. "_blocks." + str(idx) + ".",
  578. MbConvBlock(
  579. block_args.input_filters,
  580. block_args=block_args,
  581. padding_type=padding_type,
  582. use_se=use_se,
  583. name="_blocks." + str(idx) + ".",
  584. drop_connect_rate=drop_connect_rate,
  585. model_name=model_name,
  586. cur_stage=cur_stage))
  587. self.conv_seq.append(_mc_block)
  588. idx += 1
  589. if block_args.num_repeat > 1:
  590. block_args = block_args._replace(
  591. input_filters=block_args.output_filters, stride=1)
  592. for _ in range(block_args.num_repeat - 1):
  593. drop_connect_rate = self._global_params.drop_connect_rate
  594. if drop_connect_rate:
  595. drop_connect_rate *= float(idx) / block_size
  596. _mc_block = self.add_sublayer(
  597. "block." + str(idx) + ".",
  598. MbConvBlock(
  599. block_args.input_filters,
  600. block_args,
  601. padding_type=padding_type,
  602. use_se=use_se,
  603. name="_blocks." + str(idx) + ".",
  604. drop_connect_rate=drop_connect_rate,
  605. model_name=model_name,
  606. cur_stage=cur_stage))
  607. self.conv_seq.append(_mc_block)
  608. idx += 1
  609. cur_stage += 1
  610. def forward(self, inputs):
  611. x = self._conv_stem(inputs)
  612. x = F.swish(x)
  613. for _mc_block in self.conv_seq:
  614. x = _mc_block(x)
  615. return x
  616. class EfficientNet(nn.Layer):
  617. def __init__(self,
  618. name="b0",
  619. padding_type="SAME",
  620. override_params=None,
  621. use_se=True,
  622. class_dim=1000):
  623. super(EfficientNet, self).__init__()
  624. model_name = 'efficientnet-' + name
  625. self.name = name
  626. self._block_args, self._global_params = get_model_params(
  627. model_name, override_params)
  628. self.padding_type = padding_type
  629. self.use_se = use_se
  630. self._ef = ExtractFeatures(
  631. 3,
  632. self._block_args,
  633. self._global_params,
  634. self.padding_type,
  635. self.use_se,
  636. model_name=self.name)
  637. output_channels = round_filters(1280, self._global_params)
  638. if name == "b0_small" or name == "b0" or name == "b1":
  639. oup = 320
  640. elif name == "b2":
  641. oup = 352
  642. elif name == "b3":
  643. oup = 384
  644. elif name == "b4":
  645. oup = 448
  646. elif name == "b5":
  647. oup = 512
  648. elif name == "b6":
  649. oup = 576
  650. elif name == "b7":
  651. oup = 640
  652. self._conv = ConvBNLayer(
  653. oup,
  654. 1,
  655. output_channels,
  656. bn_act="swish",
  657. padding_type=self.padding_type,
  658. name="",
  659. conv_name="_conv_head",
  660. bn_name="_bn1",
  661. model_name=self.name,
  662. cur_stage=7)
  663. self._pool = AdaptiveAvgPool2D(1)
  664. if self._global_params.dropout_rate:
  665. self._drop = Dropout(
  666. p=self._global_params.dropout_rate, mode="upscale_in_train")
  667. param_attr, bias_attr = init_fc_layer("_fc")
  668. self._fc = Linear(
  669. output_channels,
  670. class_dim,
  671. weight_attr=param_attr,
  672. bias_attr=bias_attr)
  673. def forward(self, inputs):
  674. x = self._ef(inputs)
  675. x = self._conv(x)
  676. x = self._pool(x)
  677. if self._global_params.dropout_rate:
  678. x = self._drop(x)
  679. x = paddle.squeeze(x, axis=[2, 3])
  680. x = self._fc(x)
  681. return x
  682. def EfficientNetB0_small(padding_type='DYNAMIC',
  683. override_params=None,
  684. use_se=False,
  685. **args):
  686. model = EfficientNet(
  687. name='b0',
  688. padding_type=padding_type,
  689. override_params=override_params,
  690. use_se=use_se,
  691. **args)
  692. return model
  693. def EfficientNetB0(padding_type='SAME',
  694. override_params=None,
  695. use_se=True,
  696. **args):
  697. model = EfficientNet(
  698. name='b0',
  699. padding_type=padding_type,
  700. override_params=override_params,
  701. use_se=use_se,
  702. **args)
  703. return model
  704. def EfficientNetB1(padding_type='SAME',
  705. override_params=None,
  706. use_se=True,
  707. **args):
  708. model = EfficientNet(
  709. name='b1',
  710. padding_type=padding_type,
  711. override_params=override_params,
  712. use_se=use_se,
  713. **args)
  714. return model
  715. def EfficientNetB2(padding_type='SAME',
  716. override_params=None,
  717. use_se=True,
  718. **args):
  719. model = EfficientNet(
  720. name='b2',
  721. padding_type=padding_type,
  722. override_params=override_params,
  723. use_se=use_se,
  724. **args)
  725. return model
  726. def EfficientNetB3(padding_type='SAME',
  727. override_params=None,
  728. use_se=True,
  729. **args):
  730. model = EfficientNet(
  731. name='b3',
  732. padding_type=padding_type,
  733. override_params=override_params,
  734. use_se=use_se,
  735. **args)
  736. return model
  737. def EfficientNetB4(padding_type='SAME',
  738. override_params=None,
  739. use_se=True,
  740. **args):
  741. model = EfficientNet(
  742. name='b4',
  743. padding_type=padding_type,
  744. override_params=override_params,
  745. use_se=use_se,
  746. **args)
  747. return model
  748. def EfficientNetB5(padding_type='SAME',
  749. override_params=None,
  750. use_se=True,
  751. **args):
  752. model = EfficientNet(
  753. name='b5',
  754. padding_type=padding_type,
  755. override_params=override_params,
  756. use_se=use_se,
  757. **args)
  758. return model
  759. def EfficientNetB6(padding_type='SAME',
  760. override_params=None,
  761. use_se=True,
  762. **args):
  763. model = EfficientNet(
  764. name='b6',
  765. padding_type=padding_type,
  766. override_params=override_params,
  767. use_se=use_se,
  768. **args)
  769. return model
  770. def EfficientNetB7(padding_type='SAME',
  771. override_params=None,
  772. use_se=True,
  773. **args):
  774. model = EfficientNet(
  775. name='b7',
  776. padding_type=padding_type,
  777. override_params=override_params,
  778. use_se=use_se,
  779. **args)
  780. return model