rec_resnet_vd.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. # copyright (c) 2020 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. from __future__ import absolute_import
  15. from __future__ import division
  16. from __future__ import print_function
  17. import paddle
  18. from paddle import ParamAttr
  19. import paddle.nn as nn
  20. import paddle.nn.functional as F
  21. __all__ = ["ResNet"]
  22. class ConvBNLayer(nn.Layer):
  23. def __init__(
  24. self,
  25. in_channels,
  26. out_channels,
  27. kernel_size,
  28. stride=1,
  29. groups=1,
  30. is_vd_mode=False,
  31. act=None,
  32. name=None,
  33. ):
  34. super(ConvBNLayer, self).__init__()
  35. self.is_vd_mode = is_vd_mode
  36. self._pool2d_avg = nn.AvgPool2D(
  37. kernel_size=stride, stride=stride, padding=0, ceil_mode=True
  38. )
  39. self._conv = nn.Conv2D(
  40. in_channels=in_channels,
  41. out_channels=out_channels,
  42. kernel_size=kernel_size,
  43. stride=1 if is_vd_mode else stride,
  44. padding=(kernel_size - 1) // 2,
  45. groups=groups,
  46. weight_attr=ParamAttr(name=name + "_weights"),
  47. bias_attr=False,
  48. )
  49. if name == "conv1":
  50. bn_name = "bn_" + name
  51. else:
  52. bn_name = "bn" + name[3:]
  53. self._batch_norm = nn.BatchNorm(
  54. out_channels,
  55. act=act,
  56. param_attr=ParamAttr(name=bn_name + "_scale"),
  57. bias_attr=ParamAttr(bn_name + "_offset"),
  58. moving_mean_name=bn_name + "_mean",
  59. moving_variance_name=bn_name + "_variance",
  60. )
  61. def forward(self, inputs):
  62. if self.is_vd_mode:
  63. inputs = self._pool2d_avg(inputs)
  64. y = self._conv(inputs)
  65. y = self._batch_norm(y)
  66. return y
  67. class BottleneckBlock(nn.Layer):
  68. def __init__(
  69. self,
  70. in_channels,
  71. out_channels,
  72. stride,
  73. shortcut=True,
  74. if_first=False,
  75. name=None,
  76. ):
  77. super(BottleneckBlock, self).__init__()
  78. self.conv0 = ConvBNLayer(
  79. in_channels=in_channels,
  80. out_channels=out_channels,
  81. kernel_size=1,
  82. act="relu",
  83. name=name + "_branch2a",
  84. )
  85. self.conv1 = ConvBNLayer(
  86. in_channels=out_channels,
  87. out_channels=out_channels,
  88. kernel_size=3,
  89. stride=stride,
  90. act="relu",
  91. name=name + "_branch2b",
  92. )
  93. self.conv2 = ConvBNLayer(
  94. in_channels=out_channels,
  95. out_channels=out_channels * 4,
  96. kernel_size=1,
  97. act=None,
  98. name=name + "_branch2c",
  99. )
  100. if not shortcut:
  101. self.short = ConvBNLayer(
  102. in_channels=in_channels,
  103. out_channels=out_channels * 4,
  104. kernel_size=1,
  105. stride=stride,
  106. is_vd_mode=not if_first and stride[0] != 1,
  107. name=name + "_branch1",
  108. )
  109. self.shortcut = shortcut
  110. def forward(self, inputs):
  111. y = self.conv0(inputs)
  112. conv1 = self.conv1(y)
  113. conv2 = self.conv2(conv1)
  114. if self.shortcut:
  115. short = inputs
  116. else:
  117. short = self.short(inputs)
  118. y = paddle.add(x=short, y=conv2)
  119. y = F.relu(y)
  120. return y
  121. class BasicBlock(nn.Layer):
  122. def __init__(
  123. self,
  124. in_channels,
  125. out_channels,
  126. stride,
  127. shortcut=True,
  128. if_first=False,
  129. name=None,
  130. ):
  131. super(BasicBlock, self).__init__()
  132. self.stride = stride
  133. self.conv0 = ConvBNLayer(
  134. in_channels=in_channels,
  135. out_channels=out_channels,
  136. kernel_size=3,
  137. stride=stride,
  138. act="relu",
  139. name=name + "_branch2a",
  140. )
  141. self.conv1 = ConvBNLayer(
  142. in_channels=out_channels,
  143. out_channels=out_channels,
  144. kernel_size=3,
  145. act=None,
  146. name=name + "_branch2b",
  147. )
  148. if not shortcut:
  149. self.short = ConvBNLayer(
  150. in_channels=in_channels,
  151. out_channels=out_channels,
  152. kernel_size=1,
  153. stride=stride,
  154. is_vd_mode=not if_first and stride[0] != 1,
  155. name=name + "_branch1",
  156. )
  157. self.shortcut = shortcut
  158. def forward(self, inputs):
  159. y = self.conv0(inputs)
  160. conv1 = self.conv1(y)
  161. if self.shortcut:
  162. short = inputs
  163. else:
  164. short = self.short(inputs)
  165. y = paddle.add(x=short, y=conv1)
  166. y = F.relu(y)
  167. return y
  168. class ResNet(nn.Layer):
  169. def __init__(self, in_channels=3, layers=50, **kwargs):
  170. super(ResNet, self).__init__()
  171. self.layers = layers
  172. supported_layers = [18, 34, 50, 101, 152, 200]
  173. assert (
  174. layers in supported_layers
  175. ), "supported layers are {} but input layer is {}".format(
  176. supported_layers, layers
  177. )
  178. if layers == 18:
  179. depth = [2, 2, 2, 2]
  180. elif layers == 34 or layers == 50:
  181. depth = [3, 4, 6, 3]
  182. elif layers == 101:
  183. depth = [3, 4, 23, 3]
  184. elif layers == 152:
  185. depth = [3, 8, 36, 3]
  186. elif layers == 200:
  187. depth = [3, 12, 48, 3]
  188. num_channels = [64, 256, 512, 1024] if layers >= 50 else [64, 64, 128, 256]
  189. num_filters = [64, 128, 256, 512]
  190. self.conv1_1 = ConvBNLayer(
  191. in_channels=in_channels,
  192. out_channels=32,
  193. kernel_size=3,
  194. stride=1,
  195. act="relu",
  196. name="conv1_1",
  197. )
  198. self.conv1_2 = ConvBNLayer(
  199. in_channels=32,
  200. out_channels=32,
  201. kernel_size=3,
  202. stride=1,
  203. act="relu",
  204. name="conv1_2",
  205. )
  206. self.conv1_3 = ConvBNLayer(
  207. in_channels=32,
  208. out_channels=64,
  209. kernel_size=3,
  210. stride=1,
  211. act="relu",
  212. name="conv1_3",
  213. )
  214. self.pool2d_max = nn.MaxPool2D(kernel_size=3, stride=2, padding=1)
  215. self.block_list = []
  216. if layers >= 50:
  217. for block in range(len(depth)):
  218. shortcut = False
  219. for i in range(depth[block]):
  220. if layers in [101, 152, 200] and block == 2:
  221. if i == 0:
  222. conv_name = "res" + str(block + 2) + "a"
  223. else:
  224. conv_name = "res" + str(block + 2) + "b" + str(i)
  225. else:
  226. conv_name = "res" + str(block + 2) + chr(97 + i)
  227. if i == 0 and block != 0:
  228. stride = (2, 1)
  229. else:
  230. stride = (1, 1)
  231. bottleneck_block = self.add_sublayer(
  232. "bb_%d_%d" % (block, i),
  233. BottleneckBlock(
  234. in_channels=(
  235. num_channels[block]
  236. if i == 0
  237. else num_filters[block] * 4
  238. ),
  239. out_channels=num_filters[block],
  240. stride=stride,
  241. shortcut=shortcut,
  242. if_first=block == i == 0,
  243. name=conv_name,
  244. ),
  245. )
  246. shortcut = True
  247. self.block_list.append(bottleneck_block)
  248. self.out_channels = num_filters[block] * 4
  249. else:
  250. for block in range(len(depth)):
  251. shortcut = False
  252. for i in range(depth[block]):
  253. conv_name = "res" + str(block + 2) + chr(97 + i)
  254. if i == 0 and block != 0:
  255. stride = (2, 1)
  256. else:
  257. stride = (1, 1)
  258. basic_block = self.add_sublayer(
  259. "bb_%d_%d" % (block, i),
  260. BasicBlock(
  261. in_channels=(
  262. num_channels[block] if i == 0 else num_filters[block]
  263. ),
  264. out_channels=num_filters[block],
  265. stride=stride,
  266. shortcut=shortcut,
  267. if_first=block == i == 0,
  268. name=conv_name,
  269. ),
  270. )
  271. shortcut = True
  272. self.block_list.append(basic_block)
  273. self.out_channels = num_filters[block]
  274. self.out_pool = nn.MaxPool2D(kernel_size=2, stride=2, padding=0)
  275. def forward(self, inputs):
  276. y = self.conv1_1(inputs)
  277. y = self.conv1_2(y)
  278. y = self.conv1_3(y)
  279. y = self.pool2d_max(y)
  280. for block in self.block_list:
  281. y = block(y)
  282. y = self.out_pool(y)
  283. return y