hardnet.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  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/PingoLH/Pytorch-HarDNet
  15. import paddle
  16. import paddle.nn as nn
  17. from paddlex.ppcls.utils.save_load import load_dygraph_pretrain, load_dygraph_pretrain_from_url
  18. MODEL_URLS = {
  19. 'HarDNet39_ds':
  20. 'https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/HarDNet39_ds_pretrained.pdparams',
  21. 'HarDNet68_ds':
  22. 'https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/HarDNet68_ds_pretrained.pdparams',
  23. 'HarDNet68':
  24. 'https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/HarDNet68_pretrained.pdparams',
  25. 'HarDNet85':
  26. 'https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/HarDNet85_pretrained.pdparams'
  27. }
  28. __all__ = MODEL_URLS.keys()
  29. def ConvLayer(in_channels,
  30. out_channels,
  31. kernel_size=3,
  32. stride=1,
  33. bias_attr=False):
  34. layer = nn.Sequential(
  35. ('conv', nn.Conv2D(
  36. in_channels,
  37. out_channels,
  38. kernel_size=kernel_size,
  39. stride=stride,
  40. padding=kernel_size // 2,
  41. groups=1,
  42. bias_attr=bias_attr)), ('norm', nn.BatchNorm2D(out_channels)),
  43. ('relu', nn.ReLU6()))
  44. return layer
  45. def DWConvLayer(in_channels,
  46. out_channels,
  47. kernel_size=3,
  48. stride=1,
  49. bias_attr=False):
  50. layer = nn.Sequential(
  51. ('dwconv', nn.Conv2D(
  52. in_channels,
  53. out_channels,
  54. kernel_size=kernel_size,
  55. stride=stride,
  56. padding=1,
  57. groups=out_channels,
  58. bias_attr=bias_attr)), ('norm', nn.BatchNorm2D(out_channels)))
  59. return layer
  60. def CombConvLayer(in_channels, out_channels, kernel_size=1, stride=1):
  61. layer = nn.Sequential(
  62. ('layer1', ConvLayer(
  63. in_channels, out_channels, kernel_size=kernel_size)),
  64. ('layer2', DWConvLayer(
  65. out_channels, out_channels, stride=stride)))
  66. return layer
  67. class HarDBlock(nn.Layer):
  68. def __init__(self,
  69. in_channels,
  70. growth_rate,
  71. grmul,
  72. n_layers,
  73. keepBase=False,
  74. residual_out=False,
  75. dwconv=False):
  76. super().__init__()
  77. self.keepBase = keepBase
  78. self.links = []
  79. layers_ = []
  80. self.out_channels = 0 # if upsample else in_channels
  81. for i in range(n_layers):
  82. outch, inch, link = self.get_link(i + 1, in_channels, growth_rate,
  83. grmul)
  84. self.links.append(link)
  85. if dwconv:
  86. layers_.append(CombConvLayer(inch, outch))
  87. else:
  88. layers_.append(ConvLayer(inch, outch))
  89. if (i % 2 == 0) or (i == n_layers - 1):
  90. self.out_channels += outch
  91. # print("Blk out =",self.out_channels)
  92. self.layers = nn.LayerList(layers_)
  93. def get_link(self, layer, base_ch, growth_rate, grmul):
  94. if layer == 0:
  95. return base_ch, 0, []
  96. out_channels = growth_rate
  97. link = []
  98. for i in range(10):
  99. dv = 2**i
  100. if layer % dv == 0:
  101. k = layer - dv
  102. link.append(k)
  103. if i > 0:
  104. out_channels *= grmul
  105. out_channels = int(int(out_channels + 1) / 2) * 2
  106. in_channels = 0
  107. for i in link:
  108. ch, _, _ = self.get_link(i, base_ch, growth_rate, grmul)
  109. in_channels += ch
  110. return out_channels, in_channels, link
  111. def forward(self, x):
  112. layers_ = [x]
  113. for layer in range(len(self.layers)):
  114. link = self.links[layer]
  115. tin = []
  116. for i in link:
  117. tin.append(layers_[i])
  118. if len(tin) > 1:
  119. x = paddle.concat(tin, 1)
  120. else:
  121. x = tin[0]
  122. out = self.layers[layer](x)
  123. layers_.append(out)
  124. t = len(layers_)
  125. out_ = []
  126. for i in range(t):
  127. if (i == 0 and self.keepBase) or (i == t - 1) or (i % 2 == 1):
  128. out_.append(layers_[i])
  129. out = paddle.concat(out_, 1)
  130. return out
  131. class HarDNet(nn.Layer):
  132. def __init__(self,
  133. depth_wise=False,
  134. arch=85,
  135. class_num=1000,
  136. with_pool=True):
  137. super().__init__()
  138. first_ch = [32, 64]
  139. second_kernel = 3
  140. max_pool = True
  141. grmul = 1.7
  142. drop_rate = 0.1
  143. # HarDNet68
  144. ch_list = [128, 256, 320, 640, 1024]
  145. gr = [14, 16, 20, 40, 160]
  146. n_layers = [8, 16, 16, 16, 4]
  147. downSamp = [1, 0, 1, 1, 0]
  148. if arch == 85:
  149. # HarDNet85
  150. first_ch = [48, 96]
  151. ch_list = [192, 256, 320, 480, 720, 1280]
  152. gr = [24, 24, 28, 36, 48, 256]
  153. n_layers = [8, 16, 16, 16, 16, 4]
  154. downSamp = [1, 0, 1, 0, 1, 0]
  155. drop_rate = 0.2
  156. elif arch == 39:
  157. # HarDNet39
  158. first_ch = [24, 48]
  159. ch_list = [96, 320, 640, 1024]
  160. grmul = 1.6
  161. gr = [16, 20, 64, 160]
  162. n_layers = [4, 16, 8, 4]
  163. downSamp = [1, 1, 1, 0]
  164. if depth_wise:
  165. second_kernel = 1
  166. max_pool = False
  167. drop_rate = 0.05
  168. blks = len(n_layers)
  169. self.base = nn.LayerList([])
  170. # First Layer: Standard Conv3x3, Stride=2
  171. self.base.append(
  172. ConvLayer(
  173. in_channels=3,
  174. out_channels=first_ch[0],
  175. kernel_size=3,
  176. stride=2,
  177. bias_attr=False))
  178. # Second Layer
  179. self.base.append(
  180. ConvLayer(
  181. first_ch[0], first_ch[1], kernel_size=second_kernel))
  182. # Maxpooling or DWConv3x3 downsampling
  183. if max_pool:
  184. self.base.append(nn.MaxPool2D(kernel_size=3, stride=2, padding=1))
  185. else:
  186. self.base.append(DWConvLayer(first_ch[1], first_ch[1], stride=2))
  187. # Build all HarDNet blocks
  188. ch = first_ch[1]
  189. for i in range(blks):
  190. blk = HarDBlock(ch, gr[i], grmul, n_layers[i], dwconv=depth_wise)
  191. ch = blk.out_channels
  192. self.base.append(blk)
  193. if i == blks - 1 and arch == 85:
  194. self.base.append(nn.Dropout(0.1))
  195. self.base.append(ConvLayer(ch, ch_list[i], kernel_size=1))
  196. ch = ch_list[i]
  197. if downSamp[i] == 1:
  198. if max_pool:
  199. self.base.append(nn.MaxPool2D(kernel_size=2, stride=2))
  200. else:
  201. self.base.append(DWConvLayer(ch, ch, stride=2))
  202. ch = ch_list[blks - 1]
  203. layers = []
  204. if with_pool:
  205. layers.append(nn.AdaptiveAvgPool2D((1, 1)))
  206. if class_num > 0:
  207. layers.append(nn.Flatten())
  208. layers.append(nn.Dropout(drop_rate))
  209. layers.append(nn.Linear(ch, class_num))
  210. self.base.append(nn.Sequential(*layers))
  211. def forward(self, x):
  212. for layer in self.base:
  213. x = layer(x)
  214. return x
  215. def _load_pretrained(pretrained, model, model_url, use_ssld=False):
  216. if pretrained is False:
  217. pass
  218. elif pretrained is True:
  219. load_dygraph_pretrain_from_url(model, model_url, use_ssld=use_ssld)
  220. elif isinstance(pretrained, str):
  221. load_dygraph_pretrain(model, pretrained)
  222. else:
  223. raise RuntimeError(
  224. "pretrained type is not available. Please use `string` or `boolean` type."
  225. )
  226. def HarDNet39_ds(pretrained=False, **kwargs):
  227. model = HarDNet(arch=39, depth_wise=True, **kwargs)
  228. _load_pretrained(pretrained, model, MODEL_URLS["HarDNet39_ds"])
  229. return model
  230. def HarDNet68_ds(pretrained=False, **kwargs):
  231. model = HarDNet(arch=68, depth_wise=True, **kwargs)
  232. _load_pretrained(pretrained, model, MODEL_URLS["HarDNet68_ds"])
  233. return model
  234. def HarDNet68(pretrained=False, **kwargs):
  235. model = HarDNet(arch=68, **kwargs)
  236. _load_pretrained(pretrained, model, MODEL_URLS["HarDNet68"])
  237. return model
  238. def HarDNet85(pretrained=False, **kwargs):
  239. model = HarDNet(arch=85, **kwargs)
  240. _load_pretrained(pretrained, model, MODEL_URLS["HarDNet85"])
  241. return model