You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

mobilenetV2.py 9.1 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. # Copyright 2020 Huawei Technologies Co., Ltd
  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. # ============================================================================
  15. """MobileNetV2 Quant model define"""
  16. import numpy as np
  17. import mindspore.nn as nn
  18. from mindspore.ops import operations as P
  19. from mindspore import Tensor
  20. __all__ = ['mobilenetV2']
  21. def _make_divisible(v, divisor, min_value=None):
  22. if min_value is None:
  23. min_value = divisor
  24. new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
  25. # Make sure that round down does not go down by more than 10%.
  26. if new_v < 0.9 * v:
  27. new_v += divisor
  28. return new_v
  29. class GlobalAvgPooling(nn.Cell):
  30. """
  31. Global avg pooling definition.
  32. Args:
  33. Returns:
  34. Tensor, output tensor.
  35. Examples:
  36. >>> GlobalAvgPooling()
  37. """
  38. def __init__(self):
  39. super(GlobalAvgPooling, self).__init__()
  40. self.mean = P.ReduceMean(keep_dims=False)
  41. def construct(self, x):
  42. x = self.mean(x, (2, 3))
  43. return x
  44. class ConvBNReLU(nn.Cell):
  45. """
  46. Convolution/Depthwise fused with Batchnorm and ReLU block definition.
  47. Args:
  48. in_planes (int): Input channel.
  49. out_planes (int): Output channel.
  50. kernel_size (int): Input kernel size.
  51. stride (int): Stride size for the first convolutional layer. Default: 1.
  52. groups (int): channel group. Convolution is 1 while Depthiwse is input channel. Default: 1.
  53. Returns:
  54. Tensor, output tensor.
  55. Examples:
  56. >>> ConvBNReLU(16, 256, kernel_size=1, stride=1, groups=1)
  57. """
  58. def __init__(self, in_planes, out_planes, kernel_size=3, stride=1, groups=1):
  59. super(ConvBNReLU, self).__init__()
  60. padding = (kernel_size - 1) // 2
  61. self.conv = nn.Conv2dBnAct(in_planes, out_planes, kernel_size,
  62. stride=stride,
  63. pad_mode='pad',
  64. padding=padding,
  65. group=groups,
  66. has_bn=True,
  67. activation='relu')
  68. def construct(self, x):
  69. x = self.conv(x)
  70. return x
  71. class InvertedResidual(nn.Cell):
  72. """
  73. Mobilenetv2 residual block definition.
  74. Args:
  75. inp (int): Input channel.
  76. oup (int): Output channel.
  77. stride (int): Stride size for the first convolutional layer. Default: 1.
  78. expand_ratio (int): expand ration of input channel
  79. Returns:
  80. Tensor, output tensor.
  81. Examples:
  82. >>> ResidualBlock(3, 256, 1, 1)
  83. """
  84. def __init__(self, inp, oup, stride, expand_ratio):
  85. super(InvertedResidual, self).__init__()
  86. assert stride in [1, 2]
  87. hidden_dim = int(round(inp * expand_ratio))
  88. self.use_res_connect = stride == 1 and inp == oup
  89. layers = []
  90. if expand_ratio != 1:
  91. layers.append(ConvBNReLU(inp, hidden_dim, kernel_size=1))
  92. layers.extend([
  93. # dw
  94. ConvBNReLU(hidden_dim, hidden_dim,
  95. stride=stride, groups=hidden_dim),
  96. # pw-linear
  97. nn.Conv2dBnAct(hidden_dim, oup, kernel_size=1, stride=1,
  98. pad_mode='pad', padding=0, group=1, has_bn=True)
  99. ])
  100. self.conv = nn.SequentialCell(layers)
  101. self.add = P.TensorAdd()
  102. def construct(self, x):
  103. out = self.conv(x)
  104. if self.use_res_connect:
  105. out = self.add(out, x)
  106. return out
  107. class mobilenetV2(nn.Cell):
  108. """
  109. mobilenetV2 fusion architecture.
  110. Args:
  111. class_num (Cell): number of classes.
  112. width_mult (int): Channels multiplier for round to 8/16 and others. Default is 1.
  113. has_dropout (bool): Is dropout used. Default is false
  114. inverted_residual_setting (list): Inverted residual settings. Default is None
  115. round_nearest (list): Channel round to . Default is 8
  116. Returns:
  117. Tensor, output tensor.
  118. Examples:
  119. >>> mobilenetV2(num_classes=1000)
  120. """
  121. def __init__(self, num_classes=1000, width_mult=1.,
  122. has_dropout=False, inverted_residual_setting=None, round_nearest=8):
  123. super(mobilenetV2, self).__init__()
  124. block = InvertedResidual
  125. input_channel = 32
  126. last_channel = 1280
  127. # setting of inverted residual blocks
  128. self.cfgs = inverted_residual_setting
  129. if inverted_residual_setting is None:
  130. self.cfgs = [
  131. # t, c, n, s
  132. [1, 16, 1, 1],
  133. [6, 24, 2, 2],
  134. [6, 32, 3, 2],
  135. [6, 64, 4, 2],
  136. [6, 96, 3, 1],
  137. [6, 160, 3, 2],
  138. [6, 320, 1, 1],
  139. ]
  140. # building first layer
  141. input_channel = _make_divisible(
  142. input_channel * width_mult, round_nearest)
  143. self.out_channels = _make_divisible(
  144. last_channel * max(1.0, width_mult), round_nearest)
  145. features = [ConvBNReLU(3, input_channel, stride=2)]
  146. # building inverted residual blocks
  147. for t, c, n, s in self.cfgs:
  148. output_channel = _make_divisible(c * width_mult, round_nearest)
  149. for i in range(n):
  150. stride = s if i == 0 else 1
  151. features.append(
  152. block(input_channel, output_channel, stride, expand_ratio=t))
  153. input_channel = output_channel
  154. # building last several layers
  155. features.append(ConvBNReLU(
  156. input_channel, self.out_channels, kernel_size=1))
  157. # make it nn.CellList
  158. self.features = nn.SequentialCell(features)
  159. # mobilenet head
  160. head = ([GlobalAvgPooling(),
  161. nn.DenseBnAct(self.out_channels, num_classes,
  162. has_bias=True, has_bn=False)
  163. ] if not has_dropout else
  164. [GlobalAvgPooling(),
  165. nn.Dropout(0.2),
  166. nn.DenseBnAct(self.out_channels, num_classes,
  167. has_bias=True, has_bn=False)
  168. ])
  169. self.head = nn.SequentialCell(head)
  170. # init weights
  171. self.init_parameters_data()
  172. self._initialize_weights()
  173. def construct(self, x):
  174. x = self.features(x)
  175. x = self.head(x)
  176. return x
  177. def _initialize_weights(self):
  178. """
  179. Initialize weights.
  180. Args:
  181. Returns:
  182. None.
  183. Examples:
  184. >>> _initialize_weights()
  185. """
  186. self.init_parameters_data()
  187. for _, m in self.cells_and_names():
  188. np.random.seed(1)
  189. if isinstance(m, nn.Conv2d):
  190. n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
  191. w = Tensor(np.random.normal(0, np.sqrt(2. / n),
  192. m.weight.data.shape).astype("float32"))
  193. m.weight.set_data(w)
  194. if m.bias is not None:
  195. m.bias.set_data(
  196. Tensor(np.zeros(m.bias.data.shape, dtype="float32")))
  197. elif isinstance(m, nn.Conv2dBnAct):
  198. n = m.conv.kernel_size[0] * \
  199. m.conv.kernel_size[1] * m.conv.out_channels
  200. w = Tensor(np.random.normal(0, np.sqrt(2. / n),
  201. m.conv.weight.data.shape).astype("float32"))
  202. m.conv.weight.set_data(w)
  203. if m.conv.bias is not None:
  204. m.conv.bias.set_data(
  205. Tensor(np.zeros(m.conv.bias.data.shape, dtype="float32")))
  206. elif isinstance(m, nn.BatchNorm2d):
  207. m.gamma.set_data(
  208. Tensor(np.ones(m.gamma.data.shape, dtype="float32")))
  209. m.beta.set_data(
  210. Tensor(np.zeros(m.beta.data.shape, dtype="float32")))
  211. elif isinstance(m, nn.Dense):
  212. m.weight.set_data(Tensor(np.random.normal(
  213. 0, 0.01, m.weight.data.shape).astype("float32")))
  214. if m.bias is not None:
  215. m.bias.set_data(
  216. Tensor(np.zeros(m.bias.data.shape, dtype="float32")))
  217. elif isinstance(m, nn.DenseBnAct):
  218. m.dense.weight.set_data(
  219. Tensor(np.random.normal(0, 0.01, m.dense.weight.data.shape).astype("float32")))
  220. if m.dense.bias is not None:
  221. m.dense.bias.set_data(
  222. Tensor(np.zeros(m.dense.bias.data.shape, dtype="float32")))