efficientnet.py 31 KB

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