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.

nn.py 10 kB

2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. from abc import abstractmethod
  2. from .graph import Graph
  3. from .layers import (StubAdd, StubDense, StubDropout1d,
  4. StubReLU, get_batch_norm_class,
  5. get_conv_class,
  6. get_dropout_class,
  7. get_global_avg_pooling_class,
  8. get_pooling_class)
  9. from utils import Constant
  10. class NetworkGenerator:
  11. """The base class for generating a network.
  12. It can be used to generate a CNN or Multi-Layer Perceptron.
  13. Attributes:
  14. n_output_node: Number of output nodes in the network.
  15. input_shape: A tuple to represent the input shape.
  16. """
  17. def __init__(self, n_output_node, input_shape):
  18. self.n_output_node = n_output_node
  19. self.input_shape = input_shape
  20. @abstractmethod
  21. def generate(self, model_len, model_width):
  22. pass
  23. class CnnGenerator(NetworkGenerator):
  24. """A class to generate CNN.
  25. Attributes:
  26. n_dim: `len(self.input_shape) - 1`
  27. conv: A class that represents `(n_dim-1)` dimensional convolution.
  28. dropout: A class that represents `(n_dim-1)` dimensional dropout.
  29. global_avg_pooling: A class that represents `(n_dim-1)` dimensional Global Average Pooling.
  30. pooling: A class that represents `(n_dim-1)` dimensional pooling.
  31. batch_norm: A class that represents `(n_dim-1)` dimensional batch normalization.
  32. """
  33. def __init__(self, n_output_node, input_shape):
  34. super(CnnGenerator, self).__init__(n_output_node, input_shape)
  35. self.n_dim = len(self.input_shape) - 1
  36. if len(self.input_shape) > 4:
  37. raise ValueError("The input dimension is too high.")
  38. if len(self.input_shape) < 2:
  39. raise ValueError("The input dimension is too low.")
  40. self.conv = get_conv_class(self.n_dim)
  41. self.dropout = get_dropout_class(self.n_dim)
  42. self.global_avg_pooling = get_global_avg_pooling_class(self.n_dim)
  43. self.pooling = get_pooling_class(self.n_dim)
  44. self.batch_norm = get_batch_norm_class(self.n_dim)
  45. def generate(self, model_len=None, model_width=None):
  46. """Generates a CNN.
  47. Args:
  48. model_len: An integer. Number of convolutional layers.
  49. model_width: An integer. Number of filters for the convolutional layers.
  50. Returns:
  51. An instance of the class Graph. Represents the neural architecture graph of the generated model.
  52. """
  53. if model_len is None:
  54. model_len = Constant.MODEL_LEN
  55. if model_width is None:
  56. model_width = Constant.MODEL_WIDTH
  57. pooling_len = int(model_len / 4)
  58. graph = Graph(self.input_shape, False)
  59. temp_input_channel = self.input_shape[-1]
  60. output_node_id = 0
  61. stride = 1
  62. for i in range(model_len):
  63. output_node_id = graph.add_layer(StubReLU(), output_node_id)
  64. output_node_id = graph.add_layer(
  65. self.batch_norm(
  66. graph.node_list[output_node_id].shape[-1]), output_node_id
  67. )
  68. output_node_id = graph.add_layer(
  69. self.conv(
  70. temp_input_channel,
  71. model_width,
  72. kernel_size=3,
  73. stride=stride),
  74. output_node_id,
  75. )
  76. temp_input_channel = model_width
  77. if pooling_len == 0 or (
  78. (i + 1) % pooling_len == 0 and i != model_len - 1):
  79. output_node_id = graph.add_layer(
  80. self.pooling(), output_node_id)
  81. output_node_id = graph.add_layer(
  82. self.global_avg_pooling(), output_node_id)
  83. output_node_id = graph.add_layer(
  84. self.dropout(Constant.CONV_DROPOUT_RATE), output_node_id
  85. )
  86. output_node_id = graph.add_layer(
  87. StubDense(graph.node_list[output_node_id].shape[0], model_width),
  88. output_node_id,
  89. )
  90. output_node_id = graph.add_layer(StubReLU(), output_node_id)
  91. graph.add_layer(
  92. StubDense(
  93. model_width,
  94. self.n_output_node),
  95. output_node_id)
  96. return graph
  97. class ResNetGenerator(NetworkGenerator):
  98. def __init__(self, n_output_node, input_shape):
  99. super(ResNetGenerator, self).__init__(n_output_node, input_shape)
  100. # self.layers = [2, 2, 2, 2]
  101. self.in_planes = 64
  102. self.block_expansion = 1
  103. self.n_dim = len(self.input_shape) - 1
  104. if len(self.input_shape) > 4:
  105. raise ValueError('The input dimension is too high.')
  106. elif len(self.input_shape) < 2:
  107. raise ValueError('The input dimension is too low.')
  108. self.conv = get_conv_class(self.n_dim)
  109. self.dropout = get_dropout_class(self.n_dim)
  110. self.global_avg_pooling = get_global_avg_pooling_class(self.n_dim)
  111. self.adaptive_avg_pooling = get_global_avg_pooling_class(self.n_dim)
  112. self.batch_norm = get_batch_norm_class(self.n_dim)
  113. def generate(self, model_len=None, model_width=None):
  114. if model_width is None:
  115. model_width = Constant.MODEL_WIDTH
  116. graph = Graph(self.input_shape, False)
  117. temp_input_channel = self.input_shape[-1]
  118. output_node_id = 0
  119. # output_node_id = graph.add_layer(StubReLU(), output_node_id)
  120. output_node_id = graph.add_layer(self.conv(temp_input_channel, model_width, kernel_size=3), output_node_id)
  121. output_node_id = graph.add_layer(self.batch_norm(model_width), output_node_id)
  122. # output_node_id = graph.add_layer(self.pooling(kernel_size=3, stride=2, padding=1), output_node_id)
  123. output_node_id = self._make_layer(graph, model_width, 2, output_node_id, 1)
  124. model_width *= 2
  125. output_node_id = self._make_layer(graph, model_width, 2, output_node_id, 2)
  126. model_width *= 2
  127. output_node_id = self._make_layer(graph, model_width, 2, output_node_id, 2)
  128. model_width *= 2
  129. output_node_id = self._make_layer(graph, model_width, 2, output_node_id, 2)
  130. output_node_id = graph.add_layer(self.global_avg_pooling(), output_node_id)
  131. graph.add_layer(StubDense(model_width * self.block_expansion, self.n_output_node), output_node_id)
  132. return graph
  133. def _make_layer(self, graph, planes, blocks, node_id, stride):
  134. strides = [stride] + [1] * (blocks - 1)
  135. out = node_id
  136. for current_stride in strides:
  137. out = self._make_block(graph, self.in_planes, planes, out, current_stride)
  138. self.in_planes = planes * self.block_expansion
  139. return out
  140. def _make_block(self, graph, in_planes, planes, node_id, stride=1):
  141. out = graph.add_layer(self.batch_norm(in_planes), node_id)
  142. out = graph.add_layer(StubReLU(), out)
  143. residual_node_id = out
  144. out = graph.add_layer(self.conv(in_planes, planes, kernel_size=3, stride=stride), out)
  145. out = graph.add_layer(self.batch_norm(planes), out)
  146. out = graph.add_layer(StubReLU(), out)
  147. out = graph.add_layer(self.conv(planes, planes, kernel_size=3), out)
  148. residual_node_id = graph.add_layer(StubReLU(), residual_node_id)
  149. residual_node_id = graph.add_layer(self.conv(in_planes,
  150. planes * self.block_expansion,
  151. kernel_size=1,
  152. stride=stride), residual_node_id)
  153. out = graph.add_layer(StubAdd(), (out, residual_node_id))
  154. return out
  155. class MlpGenerator(NetworkGenerator):
  156. """A class to generate Multi-Layer Perceptron.
  157. """
  158. def __init__(self, n_output_node, input_shape):
  159. """Initialize the instance.
  160. Args:
  161. n_output_node: An integer. Number of output nodes in the network.
  162. input_shape: A tuple. Input shape of the network. If it is 1D, ensure the value is appended by a comma
  163. in the tuple.
  164. """
  165. super(MlpGenerator, self).__init__(n_output_node, input_shape)
  166. if len(self.input_shape) > 1:
  167. raise ValueError("The input dimension is too high.")
  168. def generate(self, model_len=None, model_width=None):
  169. """Generates a Multi-Layer Perceptron.
  170. Args:
  171. model_len: An integer. Number of hidden layers.
  172. model_width: An integer or a list of integers of length `model_len`. If it is a list, it represents the
  173. number of nodes in each hidden layer. If it is an integer, all hidden layers have nodes equal to this
  174. value.
  175. Returns:
  176. An instance of the class Graph. Represents the neural architecture graph of the generated model.
  177. """
  178. if model_len is None:
  179. model_len = Constant.MODEL_LEN
  180. if model_width is None:
  181. model_width = Constant.MODEL_WIDTH
  182. if isinstance(model_width, list) and not len(model_width) == model_len:
  183. raise ValueError(
  184. "The length of 'model_width' does not match 'model_len'")
  185. elif isinstance(model_width, int):
  186. model_width = [model_width] * model_len
  187. graph = Graph(self.input_shape, False)
  188. output_node_id = 0
  189. n_nodes_prev_layer = self.input_shape[0]
  190. for width in model_width:
  191. output_node_id = graph.add_layer(
  192. StubDense(n_nodes_prev_layer, width), output_node_id
  193. )
  194. output_node_id = graph.add_layer(
  195. StubDropout1d(Constant.MLP_DROPOUT_RATE), output_node_id
  196. )
  197. output_node_id = graph.add_layer(StubReLU(), output_node_id)
  198. n_nodes_prev_layer = width
  199. graph.add_layer(
  200. StubDense(
  201. n_nodes_prev_layer,
  202. self.n_output_node),
  203. output_node_id)
  204. return graph

一站式算法开发平台、高性能分布式深度学习框架、先进算法模型库、视觉模型炼知平台、数据可视化分析平台等一系列平台及工具,在模型高效分布式训练、数据处理和可视分析、模型炼知和轻量化等技术上形成独特优势,目前已在产学研等各领域近千家单位及个人提供AI应用赋能