hardnet.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
  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. import paddle
  15. import paddle.nn as nn
  16. import paddle.nn.functional as F
  17. from paddlex.paddleseg.cvlibs import manager
  18. from paddlex.paddleseg.models import layers
  19. from paddlex.paddleseg.utils import utils
  20. @manager.MODELS.add_component
  21. class HarDNet(nn.Layer):
  22. """
  23. [Real Time] The FC-HardDNet 70 implementation based on PaddlePaddle.
  24. The original article refers to
  25. Chao, Ping, et al. "HarDNet: A Low Memory Traffic Network"
  26. (https://arxiv.org/pdf/1909.00948.pdf)
  27. Args:
  28. num_classes (int): The unique number of target classes.
  29. stem_channels (tuple|list, optional): The number of channels before the encoder. Default: (16, 24, 32, 48).
  30. ch_list (tuple|list, optional): The number of channels at each block in the encoder. Default: (64, 96, 160, 224, 320).
  31. grmul (float, optional): The channel multiplying factor in HarDBlock, which is m in the paper. Default: 1.7.
  32. gr (tuple|list, optional): The growth rate in each HarDBlock, which is k in the paper. Default: (10, 16, 18, 24, 32).
  33. n_layers (tuple|list, optional): The number of layers in each HarDBlock. Default: (4, 4, 8, 8, 8).
  34. align_corners (bool): An argument of F.interpolate. It should be set to False when the output size of feature
  35. is even, e.g. 1024x512, otherwise it is True, e.g. 769x769. Default: False.
  36. pretrained (str, optional): The path or url of pretrained model. Default: None.
  37. """
  38. def __init__(self,
  39. num_classes,
  40. stem_channels=(16, 24, 32, 48),
  41. ch_list=(64, 96, 160, 224, 320),
  42. grmul=1.7,
  43. gr=(10, 16, 18, 24, 32),
  44. n_layers=(4, 4, 8, 8, 8),
  45. align_corners=False,
  46. pretrained=None):
  47. super().__init__()
  48. self.align_corners = align_corners
  49. self.pretrained = pretrained
  50. encoder_blks_num = len(n_layers)
  51. decoder_blks_num = encoder_blks_num - 1
  52. encoder_in_channels = stem_channels[3]
  53. self.stem = nn.Sequential(
  54. layers.ConvBNReLU(
  55. 3, stem_channels[0], kernel_size=3, bias_attr=False),
  56. layers.ConvBNReLU(
  57. stem_channels[0],
  58. stem_channels[1],
  59. kernel_size=3,
  60. bias_attr=False),
  61. layers.ConvBNReLU(
  62. stem_channels[1],
  63. stem_channels[2],
  64. kernel_size=3,
  65. stride=2,
  66. bias_attr=False),
  67. layers.ConvBNReLU(
  68. stem_channels[2],
  69. stem_channels[3],
  70. kernel_size=3,
  71. bias_attr=False))
  72. self.encoder = Encoder(encoder_blks_num, encoder_in_channels, ch_list,
  73. gr, grmul, n_layers)
  74. skip_connection_channels = self.encoder.get_skip_channels()
  75. decoder_in_channels = self.encoder.get_out_channels()
  76. self.decoder = Decoder(decoder_blks_num, decoder_in_channels,
  77. skip_connection_channels, gr, grmul, n_layers,
  78. align_corners)
  79. self.cls_head = nn.Conv2D(
  80. in_channels=self.decoder.get_out_channels(),
  81. out_channels=num_classes,
  82. kernel_size=1)
  83. self.init_weight()
  84. def forward(self, x):
  85. input_shape = paddle.shape(x)[2:]
  86. x = self.stem(x)
  87. x, skip_connections = self.encoder(x)
  88. x = self.decoder(x, skip_connections)
  89. logit = self.cls_head(x)
  90. logit = F.interpolate(
  91. logit,
  92. size=input_shape,
  93. mode="bilinear",
  94. align_corners=self.align_corners)
  95. return [logit]
  96. def init_weight(self):
  97. if self.pretrained is not None:
  98. utils.load_entire_model(self, self.pretrained)
  99. class Encoder(nn.Layer):
  100. """The Encoder implementation of FC-HardDNet 70.
  101. Args:
  102. n_blocks (int): The number of blocks in the Encoder module.
  103. in_channels (int): The number of input channels.
  104. ch_list (tuple|list): The number of channels at each block in the encoder.
  105. grmul (float): The channel multiplying factor in HarDBlock, which is m in the paper.
  106. gr (tuple|list): The growth rate in each HarDBlock, which is k in the paper.
  107. n_layers (tuple|list): The number of layers in each HarDBlock.
  108. """
  109. def __init__(self, n_blocks, in_channels, ch_list, gr, grmul, n_layers):
  110. super().__init__()
  111. self.skip_connection_channels = []
  112. self.shortcut_layers = []
  113. self.blks = nn.LayerList()
  114. ch = in_channels
  115. for i in range(n_blocks):
  116. blk = HarDBlock(ch, gr[i], grmul, n_layers[i])
  117. ch = blk.get_out_ch()
  118. self.skip_connection_channels.append(ch)
  119. self.blks.append(blk)
  120. if i < n_blocks - 1:
  121. self.shortcut_layers.append(len(self.blks) - 1)
  122. self.blks.append(
  123. layers.ConvBNReLU(
  124. ch, ch_list[i], kernel_size=1, bias_attr=False))
  125. ch = ch_list[i]
  126. if i < n_blocks - 1:
  127. self.blks.append(nn.AvgPool2D(kernel_size=2, stride=2))
  128. self.out_channels = ch
  129. def forward(self, x):
  130. skip_connections = []
  131. for i in range(len(self.blks)):
  132. x = self.blks[i](x)
  133. if i in self.shortcut_layers:
  134. skip_connections.append(x)
  135. return x, skip_connections
  136. def get_skip_channels(self):
  137. return self.skip_connection_channels
  138. def get_out_channels(self):
  139. return self.out_channels
  140. class Decoder(nn.Layer):
  141. """The Decoder implementation of FC-HardDNet 70.
  142. Args:
  143. n_blocks (int): The number of blocks in the Encoder module.
  144. in_channels (int): The number of input channels.
  145. skip_connection_channels (tuple|list): The channels of shortcut layers in encoder.
  146. grmul (float): The channel multiplying factor in HarDBlock, which is m in the paper.
  147. gr (tuple|list): The growth rate in each HarDBlock, which is k in the paper.
  148. n_layers (tuple|list): The number of layers in each HarDBlock.
  149. """
  150. def __init__(self,
  151. n_blocks,
  152. in_channels,
  153. skip_connection_channels,
  154. gr,
  155. grmul,
  156. n_layers,
  157. align_corners=False):
  158. super().__init__()
  159. prev_block_channels = in_channels
  160. self.n_blocks = n_blocks
  161. self.dense_blocks_up = nn.LayerList()
  162. self.conv1x1_up = nn.LayerList()
  163. for i in range(n_blocks - 1, -1, -1):
  164. cur_channels_count = prev_block_channels + skip_connection_channels[
  165. i]
  166. conv1x1 = layers.ConvBNReLU(
  167. cur_channels_count,
  168. cur_channels_count // 2,
  169. kernel_size=1,
  170. bias_attr=False)
  171. blk = HarDBlock(
  172. base_channels=cur_channels_count // 2,
  173. growth_rate=gr[i],
  174. grmul=grmul,
  175. n_layers=n_layers[i])
  176. self.conv1x1_up.append(conv1x1)
  177. self.dense_blocks_up.append(blk)
  178. prev_block_channels = blk.get_out_ch()
  179. self.out_channels = prev_block_channels
  180. self.align_corners = align_corners
  181. def forward(self, x, skip_connections):
  182. for i in range(self.n_blocks):
  183. skip = skip_connections.pop()
  184. x = F.interpolate(
  185. x,
  186. size=paddle.shape(skip)[2:],
  187. mode="bilinear",
  188. align_corners=self.align_corners)
  189. x = paddle.concat([x, skip], axis=1)
  190. x = self.conv1x1_up[i](x)
  191. x = self.dense_blocks_up[i](x)
  192. return x
  193. def get_out_channels(self):
  194. return self.out_channels
  195. class HarDBlock(nn.Layer):
  196. """The HarDBlock implementation
  197. Args:
  198. base_channels (int): The base channels.
  199. growth_rate (tuple|list): The growth rate.
  200. grmul (float): The channel multiplying factor.
  201. n_layers (tuple|list): The number of layers.
  202. keepBase (bool, optional): A bool value indicates whether concatenating the first layer. Default: False.
  203. """
  204. def __init__(self,
  205. base_channels,
  206. growth_rate,
  207. grmul,
  208. n_layers,
  209. keepBase=False):
  210. super().__init__()
  211. self.keepBase = keepBase
  212. self.links = []
  213. layers_ = []
  214. self.out_channels = 0
  215. for i in range(n_layers):
  216. outch, inch, link = get_link(i + 1, base_channels, growth_rate,
  217. grmul)
  218. self.links.append(link)
  219. layers_.append(
  220. layers.ConvBNReLU(
  221. inch, outch, kernel_size=3, bias_attr=False))
  222. if (i % 2 == 0) or (i == n_layers - 1):
  223. self.out_channels += outch
  224. self.layers = nn.LayerList(layers_)
  225. def forward(self, x):
  226. layers_ = [x]
  227. for layer in range(len(self.layers)):
  228. link = self.links[layer]
  229. tin = []
  230. for i in link:
  231. tin.append(layers_[i])
  232. if len(tin) > 1:
  233. x = paddle.concat(tin, axis=1)
  234. else:
  235. x = tin[0]
  236. out = self.layers[layer](x)
  237. layers_.append(out)
  238. t = len(layers_)
  239. out_ = []
  240. for i in range(t):
  241. if (i == 0 and self.keepBase) or \
  242. (i == t - 1) or (i % 2 == 1):
  243. out_.append(layers_[i])
  244. out = paddle.concat(out_, 1)
  245. return out
  246. def get_out_ch(self):
  247. return self.out_channels
  248. def get_link(layer, base_ch, growth_rate, grmul):
  249. if layer == 0:
  250. return base_ch, 0, []
  251. out_channels = growth_rate
  252. link = []
  253. for i in range(10):
  254. dv = 2**i
  255. if layer % dv == 0:
  256. k = layer - dv
  257. link.insert(0, k)
  258. if i > 0:
  259. out_channels *= grmul
  260. out_channels = int(int(out_channels + 1) / 2) * 2
  261. in_channels = 0
  262. for i in link:
  263. ch, _, _ = get_link(i, base_ch, growth_rate, grmul)
  264. in_channels += ch
  265. return out_channels, in_channels, link