xception.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  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. from paddle.nn.initializer import Uniform
  8. import math
  9. import sys
  10. __all__ = ['Xception41', 'Xception65', 'Xception71']
  11. class ConvBNLayer(nn.Layer):
  12. def __init__(self,
  13. num_channels,
  14. num_filters,
  15. filter_size,
  16. stride=1,
  17. groups=1,
  18. act=None,
  19. name=None):
  20. super(ConvBNLayer, self).__init__()
  21. self._conv = Conv2D(
  22. in_channels=num_channels,
  23. out_channels=num_filters,
  24. kernel_size=filter_size,
  25. stride=stride,
  26. padding=(filter_size - 1) // 2,
  27. groups=groups,
  28. weight_attr=ParamAttr(name=name + "_weights"),
  29. bias_attr=False)
  30. bn_name = "bn_" + name
  31. self._batch_norm = BatchNorm(
  32. num_filters,
  33. act=act,
  34. param_attr=ParamAttr(name=bn_name + "_scale"),
  35. bias_attr=ParamAttr(name=bn_name + "_offset"),
  36. moving_mean_name=bn_name + '_mean',
  37. moving_variance_name=bn_name + '_variance')
  38. def forward(self, inputs):
  39. y = self._conv(inputs)
  40. y = self._batch_norm(y)
  41. return y
  42. class SeparableConv(nn.Layer):
  43. def __init__(self, input_channels, output_channels, stride=1, name=None):
  44. super(SeparableConv, self).__init__()
  45. self._pointwise_conv = ConvBNLayer(
  46. input_channels, output_channels, 1, name=name + "_sep")
  47. self._depthwise_conv = ConvBNLayer(
  48. output_channels,
  49. output_channels,
  50. 3,
  51. stride=stride,
  52. groups=output_channels,
  53. name=name + "_dw")
  54. def forward(self, inputs):
  55. x = self._pointwise_conv(inputs)
  56. x = self._depthwise_conv(x)
  57. return x
  58. class EntryFlowBottleneckBlock(nn.Layer):
  59. def __init__(self,
  60. input_channels,
  61. output_channels,
  62. stride=2,
  63. name=None,
  64. relu_first=False):
  65. super(EntryFlowBottleneckBlock, self).__init__()
  66. self.relu_first = relu_first
  67. self._short = Conv2D(
  68. in_channels=input_channels,
  69. out_channels=output_channels,
  70. kernel_size=1,
  71. stride=stride,
  72. padding=0,
  73. weight_attr=ParamAttr(name + "_branch1_weights"),
  74. bias_attr=False)
  75. self._conv1 = SeparableConv(
  76. input_channels,
  77. output_channels,
  78. stride=1,
  79. name=name + "_branch2a_weights")
  80. self._conv2 = SeparableConv(
  81. output_channels,
  82. output_channels,
  83. stride=1,
  84. name=name + "_branch2b_weights")
  85. self._pool = MaxPool2D(kernel_size=3, stride=stride, padding=1)
  86. def forward(self, inputs):
  87. conv0 = inputs
  88. short = self._short(inputs)
  89. if self.relu_first:
  90. conv0 = F.relu(conv0)
  91. conv1 = self._conv1(conv0)
  92. conv2 = F.relu(conv1)
  93. conv2 = self._conv2(conv2)
  94. pool = self._pool(conv2)
  95. return paddle.add(x=short, y=pool)
  96. class EntryFlow(nn.Layer):
  97. def __init__(self, block_num=3):
  98. super(EntryFlow, self).__init__()
  99. name = "entry_flow"
  100. self.block_num = block_num
  101. self._conv1 = ConvBNLayer(
  102. 3, 32, 3, stride=2, act="relu", name=name + "_conv1")
  103. self._conv2 = ConvBNLayer(32, 64, 3, act="relu", name=name + "_conv2")
  104. if block_num == 3:
  105. self._conv_0 = EntryFlowBottleneckBlock(
  106. 64, 128, stride=2, name=name + "_0", relu_first=False)
  107. self._conv_1 = EntryFlowBottleneckBlock(
  108. 128, 256, stride=2, name=name + "_1", relu_first=True)
  109. self._conv_2 = EntryFlowBottleneckBlock(
  110. 256, 728, stride=2, name=name + "_2", relu_first=True)
  111. elif block_num == 5:
  112. self._conv_0 = EntryFlowBottleneckBlock(
  113. 64, 128, stride=2, name=name + "_0", relu_first=False)
  114. self._conv_1 = EntryFlowBottleneckBlock(
  115. 128, 256, stride=1, name=name + "_1", relu_first=True)
  116. self._conv_2 = EntryFlowBottleneckBlock(
  117. 256, 256, stride=2, name=name + "_2", relu_first=True)
  118. self._conv_3 = EntryFlowBottleneckBlock(
  119. 256, 728, stride=1, name=name + "_3", relu_first=True)
  120. self._conv_4 = EntryFlowBottleneckBlock(
  121. 728, 728, stride=2, name=name + "_4", relu_first=True)
  122. else:
  123. sys.exit(-1)
  124. def forward(self, inputs):
  125. x = self._conv1(inputs)
  126. x = self._conv2(x)
  127. if self.block_num == 3:
  128. x = self._conv_0(x)
  129. x = self._conv_1(x)
  130. x = self._conv_2(x)
  131. elif self.block_num == 5:
  132. x = self._conv_0(x)
  133. x = self._conv_1(x)
  134. x = self._conv_2(x)
  135. x = self._conv_3(x)
  136. x = self._conv_4(x)
  137. return x
  138. class MiddleFlowBottleneckBlock(nn.Layer):
  139. def __init__(self, input_channels, output_channels, name):
  140. super(MiddleFlowBottleneckBlock, self).__init__()
  141. self._conv_0 = SeparableConv(
  142. input_channels,
  143. output_channels,
  144. stride=1,
  145. name=name + "_branch2a_weights")
  146. self._conv_1 = SeparableConv(
  147. output_channels,
  148. output_channels,
  149. stride=1,
  150. name=name + "_branch2b_weights")
  151. self._conv_2 = SeparableConv(
  152. output_channels,
  153. output_channels,
  154. stride=1,
  155. name=name + "_branch2c_weights")
  156. def forward(self, inputs):
  157. conv0 = F.relu(inputs)
  158. conv0 = self._conv_0(conv0)
  159. conv1 = F.relu(conv0)
  160. conv1 = self._conv_1(conv1)
  161. conv2 = F.relu(conv1)
  162. conv2 = self._conv_2(conv2)
  163. return paddle.add(x=inputs, y=conv2)
  164. class MiddleFlow(nn.Layer):
  165. def __init__(self, block_num=8):
  166. super(MiddleFlow, self).__init__()
  167. self.block_num = block_num
  168. self._conv_0 = MiddleFlowBottleneckBlock(
  169. 728, 728, name="middle_flow_0")
  170. self._conv_1 = MiddleFlowBottleneckBlock(
  171. 728, 728, name="middle_flow_1")
  172. self._conv_2 = MiddleFlowBottleneckBlock(
  173. 728, 728, name="middle_flow_2")
  174. self._conv_3 = MiddleFlowBottleneckBlock(
  175. 728, 728, name="middle_flow_3")
  176. self._conv_4 = MiddleFlowBottleneckBlock(
  177. 728, 728, name="middle_flow_4")
  178. self._conv_5 = MiddleFlowBottleneckBlock(
  179. 728, 728, name="middle_flow_5")
  180. self._conv_6 = MiddleFlowBottleneckBlock(
  181. 728, 728, name="middle_flow_6")
  182. self._conv_7 = MiddleFlowBottleneckBlock(
  183. 728, 728, name="middle_flow_7")
  184. if block_num == 16:
  185. self._conv_8 = MiddleFlowBottleneckBlock(
  186. 728, 728, name="middle_flow_8")
  187. self._conv_9 = MiddleFlowBottleneckBlock(
  188. 728, 728, name="middle_flow_9")
  189. self._conv_10 = MiddleFlowBottleneckBlock(
  190. 728, 728, name="middle_flow_10")
  191. self._conv_11 = MiddleFlowBottleneckBlock(
  192. 728, 728, name="middle_flow_11")
  193. self._conv_12 = MiddleFlowBottleneckBlock(
  194. 728, 728, name="middle_flow_12")
  195. self._conv_13 = MiddleFlowBottleneckBlock(
  196. 728, 728, name="middle_flow_13")
  197. self._conv_14 = MiddleFlowBottleneckBlock(
  198. 728, 728, name="middle_flow_14")
  199. self._conv_15 = MiddleFlowBottleneckBlock(
  200. 728, 728, name="middle_flow_15")
  201. def forward(self, inputs):
  202. x = self._conv_0(inputs)
  203. x = self._conv_1(x)
  204. x = self._conv_2(x)
  205. x = self._conv_3(x)
  206. x = self._conv_4(x)
  207. x = self._conv_5(x)
  208. x = self._conv_6(x)
  209. x = self._conv_7(x)
  210. if self.block_num == 16:
  211. x = self._conv_8(x)
  212. x = self._conv_9(x)
  213. x = self._conv_10(x)
  214. x = self._conv_11(x)
  215. x = self._conv_12(x)
  216. x = self._conv_13(x)
  217. x = self._conv_14(x)
  218. x = self._conv_15(x)
  219. return x
  220. class ExitFlowBottleneckBlock(nn.Layer):
  221. def __init__(self, input_channels, output_channels1, output_channels2,
  222. name):
  223. super(ExitFlowBottleneckBlock, self).__init__()
  224. self._short = Conv2D(
  225. in_channels=input_channels,
  226. out_channels=output_channels2,
  227. kernel_size=1,
  228. stride=2,
  229. padding=0,
  230. weight_attr=ParamAttr(name + "_branch1_weights"),
  231. bias_attr=False)
  232. self._conv_1 = SeparableConv(
  233. input_channels,
  234. output_channels1,
  235. stride=1,
  236. name=name + "_branch2a_weights")
  237. self._conv_2 = SeparableConv(
  238. output_channels1,
  239. output_channels2,
  240. stride=1,
  241. name=name + "_branch2b_weights")
  242. self._pool = MaxPool2D(kernel_size=3, stride=2, padding=1)
  243. def forward(self, inputs):
  244. short = self._short(inputs)
  245. conv0 = F.relu(inputs)
  246. conv1 = self._conv_1(conv0)
  247. conv2 = F.relu(conv1)
  248. conv2 = self._conv_2(conv2)
  249. pool = self._pool(conv2)
  250. return paddle.add(x=short, y=pool)
  251. class ExitFlow(nn.Layer):
  252. def __init__(self, class_dim):
  253. super(ExitFlow, self).__init__()
  254. name = "exit_flow"
  255. self._conv_0 = ExitFlowBottleneckBlock(
  256. 728, 728, 1024, name=name + "_1")
  257. self._conv_1 = SeparableConv(1024, 1536, stride=1, name=name + "_2")
  258. self._conv_2 = SeparableConv(1536, 2048, stride=1, name=name + "_3")
  259. self._pool = AdaptiveAvgPool2D(1)
  260. stdv = 1.0 / math.sqrt(2048 * 1.0)
  261. self._out = Linear(
  262. 2048,
  263. class_dim,
  264. weight_attr=ParamAttr(
  265. name="fc_weights", initializer=Uniform(-stdv, stdv)),
  266. bias_attr=ParamAttr(name="fc_offset"))
  267. def forward(self, inputs):
  268. conv0 = self._conv_0(inputs)
  269. conv1 = self._conv_1(conv0)
  270. conv1 = F.relu(conv1)
  271. conv2 = self._conv_2(conv1)
  272. conv2 = F.relu(conv2)
  273. pool = self._pool(conv2)
  274. pool = paddle.flatten(pool, start_axis=1, stop_axis=-1)
  275. out = self._out(pool)
  276. return out
  277. class Xception(nn.Layer):
  278. def __init__(self,
  279. entry_flow_block_num=3,
  280. middle_flow_block_num=8,
  281. class_dim=1000):
  282. super(Xception, self).__init__()
  283. self.entry_flow_block_num = entry_flow_block_num
  284. self.middle_flow_block_num = middle_flow_block_num
  285. self._entry_flow = EntryFlow(entry_flow_block_num)
  286. self._middle_flow = MiddleFlow(middle_flow_block_num)
  287. self._exit_flow = ExitFlow(class_dim)
  288. def forward(self, inputs):
  289. x = self._entry_flow(inputs)
  290. x = self._middle_flow(x)
  291. x = self._exit_flow(x)
  292. return x
  293. def Xception41(**args):
  294. model = Xception(entry_flow_block_num=3, middle_flow_block_num=8, **args)
  295. return model
  296. def Xception65(**args):
  297. model = Xception(entry_flow_block_num=3, middle_flow_block_num=16, **args)
  298. return model
  299. def Xception71(**args):
  300. model = Xception(entry_flow_block_num=5, middle_flow_block_num=16, **args)
  301. return model